source: trunk/LeMillSearchTool.py @ 475

Revision 475, 8.4 KB checked in by vahur, 13 years ago (diff)

spent hours
fixing bugs

  • Property svn:eol-style set to native
Line 
1# Copyright 2006 by the LeMill Team (see AUTHORS)
2#
3# This file is part of LeMill.
4#
5# LeMill is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation; either version 2 of the License, or
8# (at your option) any later version.
9#
10# LeMill is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with LeMill; if not, write to the Free Software
17# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
19from OFS.SimpleItem import SimpleItem
20from OFS.SimpleItem import Item
21from OFS.PropertyManager import PropertyManager
22from Products.CMFCore.utils import UniqueObject
23from Globals import InitializeClass
24from AccessControl import ClassSecurityInfo
25from Products.CMFCore.utils import getToolByName
26from ZODB.PersistentMapping import PersistentMapping
27import xmlrpclib
28from socket import gaierror
29from xmlrpclib import ProtocolError
30from Acquisition import aq_base
31from config import MANAGE_PORTAL
32
33class LeMillSearchTool(PropertyManager, SimpleItem, UniqueObject):
34    """ lemill search. Performs standard plone search and xml-rpc search to query distant lemilles """
35
36    id = 'lemill_search'
37    meta_type = 'LeMillSearch'
38    security = ClassSecurityInfo()
39    plone_tool = 1
40    toolicon = 'skins/lemill/tool.gif'
41    __allow_access_to_unprotected_subobjects__ = 1
42
43    def __init__(self,id=None):
44        #using try-except to solve version incompatibility errors
45        try:
46            SimpleItem.__init__(self,id)
47        except AttributeError:
48            pass
49        try:
50            PropertyManager.__init__(self,id)
51        except AttributeError:
52            pass
53        try:
54            UniqueObject.__init__(self,id)
55        except AttributeError:
56            pass
57        self._setProperty('enable_remotesearch', True, 'boolean')
58        self.remote_lemilles = {}
59
60    def lemill_search(self, REQUEST, **kw):
61        """ lemill search method. performs local and remote searches """
62        class myremotebrain:
63            """ my brain """
64            __allow_access_to_unprotected_subobjects__=1
65            def __init__(self, ob, data):
66                self.__ob = ob
67                self.data = data
68               
69            def __get__(self, key):
70                try:
71                    return self.data[key]
72                except:
73                    print "ERROR: ", key
74
75            def __getattr__(self, key, default=''):
76                if self.data.has_key(key):
77                    return self.data[key]
78                return getattr(self.__ob, key)
79
80        results = []
81        if not kw.has_key('portal_type'):
82            # limiting search results to meta_types listed below. I wouldn't want junk on my way
83            kw['portal_type'] = ['Piece', 'PresentationMaterial', 'Tool', 'Story', 'Activity']
84        local = self.local_search(REQUEST, **kw)
85        remote = []
86        if self.getEnableRemoteSearch():
87            remote = self.remote_search(REQUEST, **kw)
88        for x in local:
89            results.append(x)
90        for y in remote:
91            rbrain = myremotebrain(aq_base(self).__of__(self),y)
92            results.append(rbrain)
93        return results
94
95    security.declarePrivate('local_search')
96    def local_search(self, REQUEST, **kw):
97        """ do a local search """
98        portal_catalog = getToolByName( self, 'portal_catalog' )
99        results = portal_catalog.searchResults(REQUEST, **kw)
100        return results
101
102    security.declarePrivate('remote_search')
103    def remote_search(self, REQUEST, **kw):
104        """ do remote search.
105            connects to distant lemill via xml-rpc and invokes incoming_query method.
106        """
107        # get remote lemill address from somewhere
108        tb_locations = self.get_urls_of_remote_lemilles()
109        result = []
110        if tb_locations is None:
111            return result
112        for tb in tb_locations:
113            ping = self.ping(tb)
114            if not ping:
115                #print "LeMill @ %s is alive!" % tb
116                # connect now!
117                r = xmlrpclib.Server(tb+'/'+self.getId(), allow_none=1)
118                query_str = REQUEST.get('QUERY_STRING')
119                query = {}
120                q_tmp = query_str.split('&')
121                params = []
122                for pair in q_tmp:
123                    key_tmp, value = pair.split('=')
124                    key = key_tmp.split('%')[0]
125                    if key not in params:
126                        params.append(key)
127                for p in params:
128                    query[p] = REQUEST.get(p)
129                #XXX: this is evil. need to find out if unix timestamps are ok here.
130                try:
131                    query['created'] = str(query['created'])
132                except KeyError:
133                    pass
134                from xmlrpclib import Fault
135                try:
136                    result += r.incoming_search(query)
137                    # Fault: <Fault -1: 'Unexpected Zope exception: exceptions.TypeError - cannot marshal   objects'>
138                except Fault:
139                    pass
140                #XXX: when passing **kw
141                #XXX: TypeError: __call__() got an unexpected keyword argument 'use_types_blacklist'
142            else:
143                print "LeMill @ %s is dead!" % tb
144        return result
145
146    security.declarePublic('incoming_search')
147    def incoming_search(self, query):
148        """ search request coming from remote lemill uses this method """
149        from DateTime import DateTime
150        #XXX: this is evil. need to find out if unix timestamps are ok here.
151        # mybrains object doesn't want to travel over xml-rpc...
152        try:
153            query['created'] = eval(query['created'])
154        except KeyError:
155            pass
156        query_results = self.local_search(query)
157        results = []
158        for x in query_results:
159            # XXX: should use schema values here?
160            results.append({'Title':x.Title,
161                    'meta_type':x.meta_type,
162                    'Description':x.Description,
163                    'pretty_title_or_id':x.pretty_title_or_id(),
164                    'Creator':x.Creator,
165                    'ModificationDate':x.ModificationDate,
166                    'getURL':x.getURL(),
167                    'portal_type':x.portal_type,
168                    'review_state':x.review_state,
169                    'data_record_normalized_score_':x.data_record_normalized_score_,
170                    'getTags':x.getTags,
171                    'Language':x.Language,
172                    })
173        return results
174
175    def get_urls_of_remote_lemilles(self):
176        """ get remote lemill locations. ie. ('http://localhost:9090/SecondLeMill',) """
177        result = []
178        for x in self.remote_lemilles.values():
179            result.append(x['URL'])
180        return result
181
182    def get_remote_lemilles(self):
183        return self.remote_lemilles
184
185    def ping(self, address):
186        """ ping remote lemill, see if it's alive """
187        address = address +'/'+ self.getId()
188        r = xmlrpclib.Server(address)
189        try:
190            remote = r.pong('ping')
191        except (ProtocolError, gaierror):
192            #print "incompatible server or failure in name resolution"
193            return 1
194        if remote != 'pong':
195            return 1
196        return 0
197
198    def pong(self, ping):
199        """ respond to ping """
200        if ping != 'ping':
201            return 1
202        return "pong"
203
204    security.declareProtected(MANAGE_PORTAL, 'setNewLocation')
205    def setNewLocation(self, location):
206        """ set remote search location and protocol """
207        import time
208        timestamp = time.time()
209        while self.remote_lemilles.has_key(str(int(timestamp))):
210            timestamp = time.time()
211        timestamp = str(int(timestamp))
212        self.remote_lemilles[timestamp] = {'URL': location, 'protocol': 'xmlrpc'}
213        self._p_changed = True
214        return 0
215
216    def delete_remote_lemill(self, id):
217        """ delete remote lemill address from our list """
218        del self.remote_lemilles[id]
219        self._p_changed = True
220
221    def getEnableRemoteSearch(self):
222        return self.enable_remotesearch
223   
224    def setEnableRemoteSearch(self, enable):
225        self.enable_remotesearch = enable
226
227
228InitializeClass(LeMillSearchTool)
Note: See TracBrowser for help on using the repository browser.