1#*************************************************************************
2#
3# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4#
5# Copyright 2000, 2010 Oracle and/or its affiliates.
6#
7# OpenOffice.org - a multi-platform office productivity suite
8#
9# This file is part of OpenOffice.org.
10#
11# OpenOffice.org is free software: you can redistribute it and/or modify
12# it under the terms of the GNU Lesser General Public License version 3
13# only, as published by the Free Software Foundation.
14#
15# OpenOffice.org is distributed in the hope that it will be useful,
16# but WITHOUT ANY WARRANTY; without even the implied warranty of
17# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18# GNU Lesser General Public License version 3 for more details
19# (a copy is included in the LICENSE file that accompanied this code).
20#
21# You should have received a copy of the GNU Lesser General Public License
22# version 3 along with OpenOffice.org.  If not, see
23# <http://www.openoffice.org/license.html>
24# for a copy of the LGPLv3 License.
25#
26#*************************************************************************
27import uno
28import unohelper
29import sys
30import imp
31import os
32from com.sun.star.uno import Exception,RuntimeException
33from com.sun.star.loader import XImplementationLoader
34from com.sun.star.lang import XServiceInfo
35
36MODULE_PROTOCOL = "vnd.openoffice.pymodule:"
37DEBUG = 0
38
39g_supportedServices  = "com.sun.star.loader.Python",      # referenced by the native C++ loader !
40g_implementationName = "org.openoffice.comp.pyuno.Loader" # referenced by the native C++ loader !
41
42def splitUrl( url ):
43      nColon = url.find( ":" )
44      if -1 == nColon:
45            raise RuntimeException( "PythonLoader: No protocol in url " + url, None )
46      return url[0:nColon], url[nColon+1:len(url)]
47
48g_loadedComponents = {}
49def checkForPythonPathBesideComponent( url ):
50      path = unohelper.fileUrlToSystemPath( url+"/pythonpath.zip" );
51      if DEBUG == 1:
52            print "checking for existence of " + encfile( path )
53      if 1 == os.access( encfile( path ), os.F_OK) and not path in sys.path:
54            if DEBUG == 1:
55                  print "adding " + encfile( path ) + " to sys.path"
56            sys.path.append( path )
57
58      path = unohelper.fileUrlToSystemPath( url+"/pythonpath" );
59      if 1 == os.access( encfile( path ), os.F_OK) and not path in sys.path:
60            if DEBUG == 1:
61                  print "adding " + encfile( path ) + " to sys.path"
62            sys.path.append( path )
63
64def encfile(uni):
65    return uni.encode( sys.getfilesystemencoding())
66
67class Loader( XImplementationLoader, XServiceInfo, unohelper.Base ):
68      def __init__(self, ctx ):
69	  if DEBUG:
70	     print "pythonloader.Loader ctor"
71	  self.ctx = ctx
72
73      def getModuleFromUrl( self, url ):
74          if DEBUG:
75                print "pythonloader: interpreting url " +url
76          protocol, dependent = splitUrl( url )
77          if "vnd.sun.star.expand" == protocol:
78                exp = self.ctx.getValueByName( "/singletons/com.sun.star.util.theMacroExpander" )
79                url = exp.expandMacros(dependent)
80                protocol,dependent = splitUrl( url )
81
82          if DEBUG:
83                print "pythonloader: after expansion " +protocol +":" + dependent
84
85          try:
86                if "file" == protocol:
87                      # remove \..\ sequence, which may be useful e.g. in the build env
88                      url = unohelper.absolutize( url, url )
89
90                      # did we load the module already ?
91                      mod = g_loadedComponents.get( url )
92                      if not mod:
93                            mod = imp.new_module("uno_component")
94
95                            # check for pythonpath.zip beside .py files
96                            checkForPythonPathBesideComponent( url[0:url.rfind('/')] )
97
98                            # read the file
99                            filename = unohelper.fileUrlToSystemPath( url )
100                            fileHandle = file( filename )
101                            src = fileHandle.read().replace("\r","")
102                            if not src.endswith( "\n" ):
103                                  src = src + "\n"
104
105                            # compile and execute the module
106                            codeobject = compile( src, encfile(filename), "exec" )
107                            exec codeobject in mod.__dict__
108                            mod.__file__ = encfile(filename)
109                            g_loadedComponents[url] = mod
110                      return mod
111                elif "vnd.openoffice.pymodule" == protocol:
112                      return  __import__( dependent )
113                else:
114                      raise RuntimeException( "PythonLoader: Unknown protocol " +
115                                              protocol + " in url " +url, self )
116          except ImportError, e:
117                raise RuntimeException( "Couldn't load "+url+ " for reason "+str(e), None)
118          return None
119
120      def activate( self, implementationName, dummy, locationUrl, regKey ):
121	  if DEBUG:
122	     print "pythonloader.Loader.activate"
123
124	  mod = self.getModuleFromUrl( locationUrl )
125          implHelper = mod.__dict__.get( "g_ImplementationHelper" , None )
126          if implHelper == None:
127		return mod.getComponentFactory( implementationName, self.ctx.ServiceManager, regKey )
128          else:
129		return implHelper.getComponentFactory( implementationName,regKey,self.ctx.ServiceManager)
130
131      def writeRegistryInfo( self, regKey, dummy, locationUrl ):
132	  if DEBUG:
133	     print "pythonloader.Loader.writeRegistryInfo"
134
135	  mod = self.getModuleFromUrl( locationUrl )
136          implHelper = mod.__dict__.get( "g_ImplementationHelper" , None )
137          if implHelper == None:
138	        return mod.writeRegistryInfo( self.ctx.ServiceManager, regKey )
139          else:
140	        return implHelper.writeRegistryInfo( regKey, self.ctx.ServiceManager )
141
142      def getImplementationName( self ):
143	  return g_implementationName
144
145      def supportsService( self, ServiceName ):
146	  return ServiceName in self.serviceNames
147
148      def getSupportedServiceNames( self ):
149	  return g_supportedServices
150
151
152