xref: /trunk/main/jvmaccess/source/classpath.cxx (revision bb3a5a855831b861943c55afcadf2a8cf42eff01)
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  *************************************************************/
21 
22 
23 
24 #include "sal/config.h"
25 
26 #include "jvmaccess/classpath.hxx"
27 
28 #include <vector>
29 
30 #include "com/sun/star/lang/IllegalArgumentException.hpp"
31 #include "com/sun/star/uno/Any.hxx"
32 #include "com/sun/star/uno/Reference.hxx"
33 #include "com/sun/star/uno/RuntimeException.hpp"
34 #include "com/sun/star/uno/XComponentContext.hpp"
35 #include "com/sun/star/uno/XInterface.hpp"
36 #include "com/sun/star/uri/UriReferenceFactory.hpp"
37 #include "com/sun/star/uri/XUriReference.hpp"
38 #include "com/sun/star/uri/XUriReferenceFactory.hpp"
39 #include "com/sun/star/uri/XVndSunStarExpandUrlReference.hpp"
40 #include "com/sun/star/util/XMacroExpander.hpp"
41 #include "osl/diagnose.h"
42 #include "rtl/uri.hxx"
43 #include "rtl/ustring.hxx"
44 #include "sal/types.h"
45 
46 #if defined SOLAR_JAVA
47 #include "jni.h"
48 #endif
49 
50 namespace {
51 
52 namespace css = ::com::sun::star;
53 
54 #if defined SOLAR_JAVA
55 // Whether a class path entry is a file: URL naming a path on this machine.
56 //
57 // On Windows, Java opens a file: URL as a UNC path, i.e. a file on another
58 // machine, in two cases:
59 //
60 // - if its authority names a host, e.g. file://host/share/a.jar;
61 // - if its path (or opaque part), once percent-decoded and with backslashes
62 //   read as slashes, starts with two slashes, e.g. file:////host/share/a.jar,
63 //   file:/%5C%5Chost/share/a.jar or file:%5C%5Chost/share/a.jar.
64 //
65 // com.sun.star.comp.sdbc.Tools enforces the same check on the Java side; keep
66 // the two in sync.
isLocalFileUrl(css::uno::Reference<css::uri::XUriReferenceFactory> const & factory,::rtl::OUString const & url)67 bool isLocalFileUrl(
68     css::uno::Reference< css::uri::XUriReferenceFactory > const & factory,
69     ::rtl::OUString const & url)
70 {
71     css::uno::Reference< css::uri::XUriReference > const uriRef(
72         factory->parse(url));
73     if (!uriRef.is()
74         || !uriRef->getScheme().equalsIgnoreAsciiCaseAsciiL(
75             RTL_CONSTASCII_STRINGPARAM("file")))
76     {
77         return false;
78     }
79     // The authority, if any, must be empty or localhost.
80     if (uriRef->hasAuthority()) {
81         ::rtl::OUString const authority(uriRef->getAuthority());
82         if (authority.getLength() != 0
83             && !authority.equalsIgnoreAsciiCaseAsciiL(
84                 RTL_CONSTASCII_STRINGPARAM("localhost")))
85         {
86             return false;
87         }
88     }
89     // The decoded path must start with exactly one slash, which also rules out
90     // the opaque form, and must contain no backslash at all.
91     ::rtl::OUString const path(
92         ::rtl::Uri::decode(
93             uriRef->getPath(), rtl_UriDecodeWithCharset,
94             RTL_TEXTENCODING_UTF8));
95     return path.getLength() >= 2 && path[0] == '/' && path[1] != '/'
96         && path.indexOf('\\') == -1;
97 }
98 #endif
99 
100 }
101 
doTranslateToUrls(css::uno::Reference<css::uno::XComponentContext> const & context,void * environment,::rtl::OUString const & classPath)102 void * ::jvmaccess::ClassPath::doTranslateToUrls(
103     css::uno::Reference< css::uno::XComponentContext > const & context,
104     void * environment, ::rtl::OUString const & classPath)
105 {
106     OSL_ASSERT(context.is() && environment != 0);
107 #if defined SOLAR_JAVA
108     ::JNIEnv * const env = static_cast< ::JNIEnv * >(environment);
109     jclass classUrl(env->FindClass("java/net/URL"));
110     if (classUrl == 0) {
111         return 0;
112     }
113     jmethodID ctorUrl(
114         env->GetMethodID(classUrl, "<init>", "(Ljava/lang/String;)V"));
115     if (ctorUrl == 0) {
116         return 0;
117     }
118     css::uno::Reference< css::uri::XUriReferenceFactory > const factory(
119         css::uri::UriReferenceFactory::create(context));
120     ::std::vector< jobject > urls;
121     for (::sal_Int32 i = 0; i != -1;) {
122         ::rtl::OUString url(classPath.getToken(0, ' ', i));
123         if (url.getLength() != 0) {
124             css::uno::Reference< css::uri::XVndSunStarExpandUrlReference >
125                 expUrl(factory->parse(url), css::uno::UNO_QUERY);
126             if (expUrl.is()) {
127                 css::uno::Reference< css::util::XMacroExpander > expander(
128                     context->getValueByName(
129                         ::rtl::OUString(
130                             RTL_CONSTASCII_USTRINGPARAM(
131                                 "/singletons/"
132                                 "com.sun.star.util.theMacroExpander"))),
133                     css::uno::UNO_QUERY_THROW);
134                 try {
135                     url = expUrl->expand(expander);
136                 } catch (css::lang::IllegalArgumentException & e) {
137                     throw css::uno::RuntimeException(
138                         (::rtl::OUString(
139                             RTL_CONSTASCII_USTRINGPARAM(
140                                 "com.sun.star.lang.IllegalArgumentException: "))
141                          + e.Message),
142                         css::uno::Reference< css::uno::XInterface >());
143                 }
144             }
145             // Add only local entries; a non-local one is logged and skipped.
146             if (!isLocalFileUrl(factory, url))
147             {
148                 OSL_TRACE(
149                     "jvmaccess::ClassPath: skipping non-local class path"
150                     " entry: %s",
151                     ::rtl::OUStringToOString(
152                         url, RTL_TEXTENCODING_ASCII_US).getStr());
153                 continue;
154             }
155             jvalue arg;
156             arg.l = env->NewString(
157                 static_cast< jchar const * >(url.getStr()),
158                 static_cast< jsize >(url.getLength()));
159             if (arg.l == 0) {
160                 return 0;
161             }
162             jobject o(env->NewObjectA(classUrl, ctorUrl, &arg));
163             if (o == 0) {
164                 return 0;
165             }
166             urls.push_back(o);
167         }
168     }
169     jobjectArray result = env->NewObjectArray(
170         static_cast< jsize >(urls.size()), classUrl, 0);
171         // static_cast is ok, as each element of urls occupied at least one
172         // character of the ::rtl::OUString classPath
173     if (result == 0) {
174         return 0;
175     }
176     jsize idx = 0;
177     for (std::vector< jobject >::iterator i(urls.begin()); i != urls.end(); ++i)
178     {
179         env->SetObjectArrayElement(result, idx++, *i);
180     }
181     return result;
182 #else
183     return 0;
184 #endif
185 }
186 
doLoadClass(css::uno::Reference<css::uno::XComponentContext> const & context,void * environment,::rtl::OUString const & classPath,::rtl::OUString const & name)187 void * ::jvmaccess::ClassPath::doLoadClass(
188     css::uno::Reference< css::uno::XComponentContext > const & context,
189     void * environment, ::rtl::OUString const & classPath,
190     ::rtl::OUString const & name)
191 {
192     OSL_ASSERT(context.is() && environment != 0);
193 #if defined SOLAR_JAVA
194     ::JNIEnv * const env = static_cast< ::JNIEnv * >(environment);
195     jclass classLoader(env->FindClass("java/net/URLClassLoader"));
196     if (classLoader == 0) {
197         return 0;
198     }
199     jmethodID ctorLoader(
200         env->GetMethodID(classLoader, "<init>", "([Ljava/net/URL;)V"));
201     if (ctorLoader == 0) {
202         return 0;
203     }
204     jvalue arg;
205     arg.l = translateToUrls(context, env, classPath);
206     if (arg.l == 0) {
207         return 0;
208     }
209     jobject cl = env->NewObjectA(classLoader, ctorLoader, &arg);
210     if (cl == 0) {
211         return 0;
212     }
213     jmethodID methLoadClass(
214         env->GetMethodID(
215             classLoader, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;"));
216     if (methLoadClass == 0) {
217         return 0;
218     }
219     arg.l = env->NewString(
220         static_cast< jchar const * >(name.getStr()),
221         static_cast< jsize >(name.getLength()));
222     if (arg.l == 0) {
223         return 0;
224     }
225     return env->CallObjectMethodA(cl, methLoadClass, &arg);
226 #else
227     return 0;
228 #endif
229 }
230