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