##############################################################################
# 
# Zope Public License (ZPL) Version 1.0
# -------------------------------------
# 
# Copyright (c) Digital Creations.  All rights reserved.
# 
# This license has been certified as Open Source(tm).
# 
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
# 
# 1. Redistributions in source code must retain the above copyright
#    notice, this list of conditions, and the following disclaimer.
# 
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions, and the following disclaimer in
#    the documentation and/or other materials provided with the
#    distribution.
# 
# 3. Digital Creations requests that attribution be given to Zope
#    in any manner possible. Zope includes a "Powered by Zope"
#    button that is installed by default. While it is not a license
#    violation to remove this button, it is requested that the
#    attribution remain. A significant investment has been put
#    into Zope, and this effort will continue if the Zope community
#    continues to grow. This is one way to assure that growth.
# 
# 4. All advertising materials and documentation mentioning
#    features derived from or use of this software must display
#    the following acknowledgement:
# 
#      "This product includes software developed by Digital Creations
#      for use in the Z Object Publishing Environment
#      (http://www.zope.org/)."
# 
#    In the event that the product being advertised includes an
#    intact Zope distribution (with copyright and license included)
#    then this clause is waived.
# 
# 5. Names associated with Zope or Digital Creations must not be used to
#    endorse or promote products derived from this software without
#    prior written permission from Digital Creations.
# 
# 6. Modified redistributions of any form whatsoever must retain
#    the following acknowledgment:
# 
#      "This product includes software developed by Digital Creations
#      for use in the Z Object Publishing Environment
#      (http://www.zope.org/)."
# 
#    Intact (re-)distributions of any official Zope release do not
#    require an external acknowledgement.
# 
# 7. Modifications are encouraged but must be packaged separately as
#    patches to official Zope releases.  Distributions that do not
#    clearly separate the patches from the original work must be clearly
#    labeled as unofficial distributions.  Modifications which do not
#    carry the name Zope may be packaged in any form, as long as they
#    conform to all of the clauses above.
# 
# 
# Disclaimer
# 
#   THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY
#   EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
#   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
#   PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL DIGITAL CREATIONS OR ITS
#   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
#   USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
#   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
#   OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
#   OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
#   SUCH DAMAGE.
# 
# 
# This software consists of contributions made by Digital Creations and
# many individuals on behalf of Digital Creations.  Specific
# attributions are listed in the accompanying credits file.
# 
##############################################################################

"""SOAP Method Product

This product provides support for external SOAP methods, which allow
domain-specific customization of web environments over server areas.
"""
__version__='$Revision: 1.6 $'[11:-2]
from Globals import Persistent, DTMLFile, MessageDialog, HTML
import OFS.SimpleItem, Acquisition
from string import split, join, find, lower
import AccessControl.Role, sys, os, stat, traceback
from OFS.SimpleItem import pretty_tb
from App.Extensions import getObject, getPath, FuncCode
#from Globals import DevelopmentMode
from App.Management import Navigation
from OFS.Cache import Cacheable

from SOAPpy import SOAPProxy

_marker = []  # Create a new marker object

manage_addSOAPMethodForm=DTMLFile('dtml/methodAdd', globals())

def manage_addSOAPMethod(self, id, title, endpoint, function,
        namespace='', soapaction='', encoding='', proxy='', REQUEST=None):
    """Add an external method to a folder
  
    In addition to the standard object-creation arguments,
    'id' and title, the following arguments are defined:

        function -- The name of the python function. This can be a
          an ordinary Python function, or a bound method.

        endpoint -- The communication endpoint

        proxy -- The host:port definition of the proxy to use

    """
    id=str(id)
    title=str(title)
    endpoint=str(endpoint)
    function=str(function)
    namespace=str(namespace)
    if namespace == '' or namespace == 'None':
        namespace=None
    soapaction=str(soapaction)
    encoding=str(encoding)
    if encoding == '' or encoding == 'None':
        encoding=None
    proxy=str(proxy)
    
    i=SOAPMethod(id,title,endpoint,function,namespace,soapaction,encoding,proxy)
    self._setObject(id,i)
    return self.manage_main(self,REQUEST)

class SOAPMethod(OFS.SimpleItem.Item, Persistent, Acquisition.Explicit,
                     AccessControl.Role.RoleManager, Navigation,Cacheable):
    """Web-callable functions that encapsulate external python functions.

    The function is defined on an external SOAP server. It is accessed
    over http using the SOAPpy module.

    """

    meta_type='SOAP Method'

    ZopeTime=Acquisition.Acquired
    HelpSys=Acquisition.Acquired

    manage_options=(
        (
        {'label':'Properties', 'action':'manage_main',
         'help':('SOAPMethod','SOAPMethodProperties.stx')},
        {'label':'Test', 'action':'',
         'help':('SOAPMethod','SOAPMethodTest.stx')},
        )
        +OFS.SimpleItem.Item.manage_options
        +AccessControl.Role.RoleManager.manage_options
        +Cacheable.manage_options
        )

    __ac_permissions__=(
        ('View management screens', ('manage_main',)),
        ('Change SOAP Methods', ('manage_edit',)),
        ('View', ('__call__','')),
        )

    def __init__(self, id, title, endpoint, function, namespace,
            soapaction, encoding, proxy=''):
        self.id=id
        self.manage_edit(title, endpoint, function, namespace,
                soapaction, encoding, proxy)

    def __setstate__(self, state):
        SOAPMethod.inheritedAttribute('__setstate__')(self, state)
        if not hasattr(self, '_namespace'):
            self._namespace = None
        if not hasattr(self, '_soapaction'):
            self._soapaction = ''
        if not hasattr(self, '_encoding'):
            self._encoding = 'UTF-8'

    manage_main=DTMLFile('dtml/methodEdit', globals())

    def manage_edit(self, title, endpoint, function,
            namespace='', soapaction='', encoding='', proxy='', REQUEST=None):
        """Change the SOAP method

        See the description of manage_addSOAPMethod for a
        descriotion of the arguments 'endpoint', 'function' and 'proxy'.
        """
        title=str(title)
        endpoint=str(endpoint)
        function=str(function)
        namespace=str(namespace)
        if namespace == '' or namespace == 'None':
            namespace=None
        soapaction=str(soapaction)
        encoding=str(encoding)
        if encoding == '' or encoding == 'None':
            encoding=None
        proxy=str(proxy)
    
        self.title=title
        self._endpoint=endpoint
        self._function=function
        self._namespace=namespace
        self._soapaction=soapaction
        self._encoding=encoding
        self._proxy=proxy
        self.ZCacheable_invalidate()
        if REQUEST:
            message="SOAP Method connected."
            return self.manage_main(self,REQUEST,manage_tabs_message=message)

    def __call__(self, *args, **kw):
        """Call an SOAPMethod

        Calling an SOAP Method is roughly equivalent to calling
        the original actual function from Python.  Positional and
        keyword parameters can be passed as usual.  Note however that
        unlike the case of a normal Python method, the "self" argument
        must be passed explicitly. And since the resulting function might
        be written in another language, you have to watch your data types.
        """

        __traceback_info__=args, kw
        # Retrieve the value from the cache.
        keyset = None
        if self.ZCacheable_isCachingEnabled():
            # Prepare a cache key.
            keyset = kw.copy()
            keyset['*'] = args
            result = self.ZCacheable_get(keywords=keyset, default=_marker)
            if result is not _marker:
                # Got a cached value.
                return result

        server = SOAPProxy(self._endpoint,
                namespace=self._namespace,
                soapaction=self._soapaction,
                encoding=self._encoding,
                http_proxy=self._proxy)
        results = apply(server.__getattr__(self._function), args, kw)
        if keyset is not None:
            if results is not None:
                self.ZCacheable_set(results, keywords=keyset)
        return results

    def function(self): return self._function
    def endpoint(self): return self._endpoint
    def namespace(self): return self._namespace
    def soapaction(self): return self._soapaction
    def encoding(self): return self._encoding
    def proxy(self): return self._proxy

