root/trunk/LeMillSearchTool.py

Revision 2409, 9.5 kB (checked in by anonymous, 4 years ago)

Worked on #1743. ***Important*** Update first to latest tagged release ([2408]) and run archetype update and quickinstaller there before doing anything with this version. Major changes: removed workflows, created LeMillCatalogTool? to provide simpler, faster catalog, replaced Plone's globalize with simpler, faster version, removed reliance to Plone's Actions in page templates, simplified access to portlets Still to do: go through portlets code and remove slow and cumbersome checks and see if they all work.

  • 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
19 from OFS.SimpleItem import SimpleItem
20 from OFS.SimpleItem import Item
21 from OFS.PropertyManager import PropertyManager
22 from Products.CMFCore.utils import UniqueObject
23 from Globals import InitializeClass
24 from AccessControl import ClassSecurityInfo
25 from Products.CMFCore.utils import getToolByName
26 from ZODB.PersistentMapping import PersistentMapping
27 import xmlrpclib
28 from socket import gaierror
29 from xmlrpclib import ProtocolError
30 from Acquisition import aq_base
31 from config import MANAGE_PORTAL, ALL_CONTENT_TYPES
32
33 class myremotebrain:
34     """ my brain """
35     __allow_access_to_unprotected_subobjects__=1
36     def __init__(self, ob, data):
37         self.__ob = ob
38         self.data = data
39         self.meta_type = self.data['meta_type']
40        
41     #def __get__(self, key):
42     #    try:
43     #        return self.data[key]
44     #    except:
45     #        print "ERROR: ", key
46
47     def __get__(self, value):
48         """ bobo """
49         try:
50             return self.data[name]
51         except:
52             raise 'aiai'
53
54     def getURL(self):
55         """ get url """
56         return self.data['getURL']
57
58     def __getitem__(self, name):
59         """ get item """
60         try:
61             return self.data[name]
62         except:
63             raise 'getitem1'
64         raise 'getitem2'
65
66     def getPortalTypeName(self):
67         """ portal type """
68         return self.data['meta_type']
69
70     def getObject(self):
71         """ fake """
72         return self
73
74     def getCoverImage(self):
75         """ get coverimage """
76         class coverImage:
77             __allow_access_to_unprotected_subobjects__=1
78             def __init__(self, url):
79                 self.url = url
80             def absolute_url(self):
81                 return self.url+'/coverImage'
82         return coverImage(self.data['getURL'])
83
84 class LeMillSearchTool(PropertyManager, SimpleItem, UniqueObject):
85     """ lemill search. Performs standard plone search and xml-rpc search to query distant lemilles """
86
87     id = 'lemill_search'
88     meta_type = 'LeMillSearch'
89     security = ClassSecurityInfo()
90     plone_tool = 1
91     toolicon = 'skins/lemill/tool.gif'
92     __allow_access_to_unprotected_subobjects__ = 1
93
94     def __init__(self,id=None):
95         #using try-except to solve version incompatibility errors
96         try:
97             SimpleItem.__init__(self,id)
98         except AttributeError:
99             pass
100         try:
101             PropertyManager.__init__(self,id)
102         except AttributeError:
103             pass
104         try:
105             UniqueObject.__init__(self,id)
106         except AttributeError:
107             pass
108         self._setProperty('enable_remotesearch', True, 'boolean')
109         self.remote_lemilles = {}
110
111
112     ### Not used
113     def lemill_search(self, REQUEST, **kw):
114         """ lemill search method. performs local and remote searches """
115         results = []
116         if not kw.has_key('portal_type'):
117             # limiting search results to meta_types listed below. I wouldn't want junk on my way
118             kw['portal_type'] = ALL_CONTENT_TYPES
119         if not kw.has_key('getState'):
120             kw['getState'] = ('public','draft')
121         local = self.local_search(REQUEST, **kw)
122         remote = []
123         show_deleted=False
124         if self.getEnableRemoteSearch():
125             remote = self.remote_search(REQUEST, **kw)
126         for x in local:
127             results.append(x)
128         for y in remote:
129             rbrain = myremotebrain(aq_base(self).__of__(self),y)
130             results.append(rbrain)
131         return results
132
133     security.declarePrivate('local_search')
134     def local_search(self, REQUEST, **kw):
135         """ do a local search """
136         portal_catalog = getToolByName( self, 'portal_catalog' )
137         results = portal_catalog.searchResults(REQUEST, **kw)
138         return results
139
140     security.declarePrivate('remote_search')
141     def remote_search(self, REQUEST, **kw):
142         """ do remote search.
143             connects to distant lemill via xml-rpc and invokes incoming_query method.
144         """
145         # get remote lemill address from somewhere
146         tb_locations = self.get_urls_of_remote_lemilles()
147         result = []
148         if tb_locations is None:
149             return result
150         for tb in tb_locations:
151             ping = self.ping(tb)
152             if not ping:
153                 #print "LeMill @ %s is alive!" % tb
154                 # connect now!
155                 r = xmlrpclib.Server(tb+'/'+self.getId(), allow_none=1)
156                 query_str = REQUEST.get('QUERY_STRING')
157                 query = {}
158                 q_tmp = query_str.split('&')
159                 params = []
160                 for pair in q_tmp:
161                     key_tmp, value = pair.split('=')
162                     key = key_tmp.split('%')[0]
163                     if key not in params:
164                         params.append(key)
165                 for p in params:
166                     query[p] = REQUEST.get(p)
167                 #XXX: this is evil. need to find out if unix timestamps are ok here.
168                 try:
169                     query['created'] = str(query['created'])
170                 except KeyError:
171                     pass
172                 from xmlrpclib import Fault
173                 try:
174                     result += r.incoming_search(query)
175                     # Fault: <Fault -1: 'Unexpected Zope exception: exceptions.TypeError - cannot marshal   objects'>
176                 except Fault:
177                     pass
178                 #XXX: when passing **kw
179                 #XXX: TypeError: __call__() got an unexpected keyword argument 'use_types_blacklist'
180             else:
181                 print "LeMill @ %s is dead!" % tb
182         return result
183
184     security.declarePublic('incoming_search')
185     def incoming_search(self, query):
186         """ search request coming from remote lemill uses this method """
187         from DateTime import DateTime
188         #XXX: this is evil. need to find out if unix timestamps are ok here.
189         # mybrains object doesn't want to travel over xml-rpc...
190         try:
191             query['created'] = eval(query['created'])
192         except KeyError:
193             pass
194         query_results = self.local_search(query)
195         results = []
196         for x in query_results:
197             # XXX: should use schema values here?
198             rr = {'Title':x.Title,
199                     'meta_type':x.meta_type,
200                     'Description':x.Description,
201                     'pretty_title_or_id':x.pretty_title_or_id(),
202                     'Creator':x.Creator,
203                     'ModificationDate':x.ModificationDate,
204                     'getURL':x.getURL(),
205                     'portal_type':x.portal_type,
206                     'getState':x.getState,
207                     'data_record_normalized_score_':x.data_record_normalized_score_,
208                     'getTags':x.getTags,
209                     'Language':x.Language,
210                     'absolute_url':x.getURL(),
211                     'getURL':x.getURL(),
212                     'getHasCoverImage' : x.getHasCoverImage,
213                     }
214             results.append(rr)
215         return results
216
217     def get_urls_of_remote_lemilles(self):
218         # get remote lemill locations. ie. ('http://localhost:9090/SecondLeMill',)
219         result = []
220         for x in self.remote_lemilles.values():
221             result.append(x['URL'])
222         return result
223
224     def get_remote_lemilles(self):
225         return self.remote_lemilles
226
227     def ping(self, address):
228         # ping remote lemill, see if it's alive
229         address = address +'/'+ self.getId()
230         r = xmlrpclib.Server(address)
231         try:
232             remote = r.pong('ping')
233         except (ProtocolError, gaierror):
234             #print "incompatible server or failure in name resolution"
235             return 1
236         except:
237             return 1
238         if remote != 'pong':
239             return 1
240         return 0
241
242     def pong(self, ping):
243         """ respond to ping """
244         if ping != 'ping':
245             return 1
246         return "pong"
247
248     security.declareProtected(MANAGE_PORTAL, 'setNewLocation')
249     def setNewLocation(self, location):
250         """ set remote search location and protocol """
251         import time
252         timestamp = time.time()
253         while self.remote_lemilles.has_key(str(int(timestamp))):
254             timestamp = time.time()
255         timestamp = str(int(timestamp))
256         self.remote_lemilles[timestamp] = {'URL': location, 'protocol': 'xmlrpc'}
257         self._p_changed = True
258         return 0
259
260     security.declareProtected(MANAGE_PORTAL, 'delete_remote_lemill')
261     def delete_remote_lemill(self, id):
262         # delete remote lemill address from our list
263         del self.remote_lemilles[id]
264         self._p_changed = True
265
266     def getEnableRemoteSearch(self):
267         return self.enable_remotesearch
268    
269     security.declareProtected(MANAGE_PORTAL, 'setEnableRemoteSearch')
270     def setEnableRemoteSearch(self, enable):
271         self.enable_remotesearch = enable
272
273
274 InitializeClass(LeMillSearchTool)
Note: See TracBrowser for help on using the browser.