1#**************************************************************
2#
3#  Licensed to the Apache Software Foundation (ASF) under one
4#  or more contributor license agreements.  See the NOTICE file
5#  distributed with this work for additional information
6#  regarding copyright ownership.  The ASF licenses this file
7#  to you under the Apache License, Version 2.0 (the
8#  "License"); you may not use this file except in compliance
9#  with the License.  You may obtain a copy of the License at
10#
11#    http://www.apache.org/licenses/LICENSE-2.0
12#
13#  Unless required by applicable law or agreed to in writing,
14#  software distributed under the License is distributed on an
15#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16#  KIND, either express or implied.  See the License for the
17#  specific language governing permissions and limitations
18#  under the License.
19#
20#**************************************************************
21import uno
22import unohelper
23import sys
24import imp
25import os
26from com.sun.star.uno import Exception,RuntimeException
27from com.sun.star.loader import XImplementationLoader
28from com.sun.star.lang import XServiceInfo
29
30MODULE_PROTOCOL = "vnd.openoffice.pymodule:"
31DEBUG = 0
32
33g_supportedServices  = "com.sun.star.loader.Python",      # referenced by the native C++ loader !
34g_implementationName = "org.openoffice.comp.pyuno.Loader" # referenced by the native C++ loader !
35
36def splitUrl( url ):
37      nColon = url.find( ":" )
38      if -1 == nColon:
39            raise RuntimeException( "PythonLoader: No protocol in url " + url, None )
40      return url[0:nColon], url[nColon+1:len(url)]
41
42g_loadedComponents = {}
43def checkForPythonPathBesideComponent( url ):
44      path = unohelper.fileUrlToSystemPath( url+"/pythonpath.zip" );
45      if DEBUG == 1:
46            print "checking for existence of " + encfile( path )
47      if 1 == os.access( encfile( path ), os.F_OK) and not path in sys.path:
48            if DEBUG == 1:
49                  print "adding " + encfile( path ) + " to sys.path"
50            sys.path.append( path )
51
52      path = unohelper.fileUrlToSystemPath( url+"/pythonpath" );
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
58def encfile(uni):
59    return uni.encode( sys.getfilesystemencoding())
60
61class Loader( XImplementationLoader, XServiceInfo, unohelper.Base ):
62      def __init__(self, ctx ):
63	  if DEBUG:
64	     print "pythonloader.Loader ctor"
65	  self.ctx = ctx
66
67      def getModuleFromUrl( self, url ):
68          if DEBUG:
69                print "pythonloader: interpreting url " +url
70          protocol, dependent = splitUrl( url )
71          if "vnd.sun.star.expand" == protocol:
72                exp = self.ctx.getValueByName( "/singletons/com.sun.star.util.theMacroExpander" )
73                url = exp.expandMacros(dependent)
74                protocol,dependent = splitUrl( url )
75
76          if DEBUG:
77                print "pythonloader: after expansion " +protocol +":" + dependent
78
79          try:
80                if "file" == protocol:
81                      # remove \..\ sequence, which may be useful e.g. in the build env
82                      url = unohelper.absolutize( url, url )
83
84                      # did we load the module already ?
85                      mod = g_loadedComponents.get( url )
86                      if not mod:
87                            mod = imp.new_module("uno_component")
88
89                            # check for pythonpath.zip beside .py files
90                            checkForPythonPathBesideComponent( url[0:url.rfind('/')] )
91
92                            # read the file
93                            filename = unohelper.fileUrlToSystemPath( url )
94                            fileHandle = file( filename )
95                            src = fileHandle.read().replace("\r","")
96                            if not src.endswith( "\n" ):
97                                  src = src + "\n"
98
99                            # compile and execute the module
100                            codeobject = compile( src, encfile(filename), "exec" )
101                            exec codeobject in mod.__dict__
102                            mod.__file__ = encfile(filename)
103                            g_loadedComponents[url] = mod
104                      return mod
105                elif "vnd.openoffice.pymodule" == protocol:
106                      return  __import__( dependent )
107                else:
108                      raise RuntimeException( "PythonLoader: Unknown protocol " +
109                                              protocol + " in url " +url, self )
110          except ImportError, e:
111                raise RuntimeException( "Couldn't load "+url+ " for reason "+str(e), None)
112          return None
113
114      def activate( self, implementationName, dummy, locationUrl, regKey ):
115	  if DEBUG:
116	     print "pythonloader.Loader.activate"
117
118	  mod = self.getModuleFromUrl( locationUrl )
119          implHelper = mod.__dict__.get( "g_ImplementationHelper" , None )
120          if implHelper == None:
121		return mod.getComponentFactory( implementationName, self.ctx.ServiceManager, regKey )
122          else:
123		return implHelper.getComponentFactory( implementationName,regKey,self.ctx.ServiceManager)
124
125      def writeRegistryInfo( self, regKey, dummy, locationUrl ):
126	  if DEBUG:
127	     print "pythonloader.Loader.writeRegistryInfo"
128
129	  mod = self.getModuleFromUrl( locationUrl )
130          implHelper = mod.__dict__.get( "g_ImplementationHelper" , None )
131          if implHelper == None:
132	        return mod.writeRegistryInfo( self.ctx.ServiceManager, regKey )
133          else:
134	        return implHelper.writeRegistryInfo( regKey, self.ctx.ServiceManager )
135
136      def getImplementationName( self ):
137	  return g_implementationName
138
139      def supportsService( self, ServiceName ):
140	  return ServiceName in self.serviceNames
141
142      def getSupportedServiceNames( self ):
143	  return g_supportedServices
144
145
146