jaroslav@123
|
1 |
/**
|
jaroslav@358
|
2 |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
|
jaroslav@123
|
3 |
*
|
jaroslav@551
|
4 |
* Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
|
jaroslav@123
|
5 |
*
|
jaroslav@358
|
6 |
* Oracle and Java are registered trademarks of Oracle and/or its affiliates.
|
jaroslav@358
|
7 |
* Other names may be trademarks of their respective owners.
|
jaroslav@123
|
8 |
*
|
jaroslav@358
|
9 |
* The contents of this file are subject to the terms of either the GNU
|
jaroslav@358
|
10 |
* General Public License Version 2 only ("GPL") or the Common
|
jaroslav@358
|
11 |
* Development and Distribution License("CDDL") (collectively, the
|
jaroslav@358
|
12 |
* "License"). You may not use this file except in compliance with the
|
jaroslav@358
|
13 |
* License. You can obtain a copy of the License at
|
jaroslav@358
|
14 |
* http://www.netbeans.org/cddl-gplv2.html
|
jaroslav@358
|
15 |
* or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
|
jaroslav@358
|
16 |
* specific language governing permissions and limitations under the
|
jaroslav@358
|
17 |
* License. When distributing the software, include this License Header
|
jaroslav@358
|
18 |
* Notice in each file and include the License file at
|
jaroslav@358
|
19 |
* nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
|
jaroslav@358
|
20 |
* particular file as subject to the "Classpath" exception as provided
|
jaroslav@358
|
21 |
* by Oracle in the GPL Version 2 section of the License file that
|
jaroslav@358
|
22 |
* accompanied this code. If applicable, add the following below the
|
jaroslav@358
|
23 |
* License Header, with the fields enclosed by brackets [] replaced by
|
jaroslav@358
|
24 |
* your own identifying information:
|
jaroslav@358
|
25 |
* "Portions Copyrighted [year] [name of copyright owner]"
|
jaroslav@358
|
26 |
*
|
jaroslav@358
|
27 |
* Contributor(s):
|
jaroslav@358
|
28 |
*
|
jaroslav@358
|
29 |
* The Original Software is NetBeans. The Initial Developer of the Original
|
jaroslav@551
|
30 |
* Software is Oracle. Portions Copyright 2013-2014 Oracle. All Rights Reserved.
|
jaroslav@358
|
31 |
*
|
jaroslav@358
|
32 |
* If you wish your version of this file to be governed by only the CDDL
|
jaroslav@358
|
33 |
* or only the GPL Version 2, indicate your decision by adding
|
jaroslav@358
|
34 |
* "[Contributor] elects to include this software in this distribution
|
jaroslav@358
|
35 |
* under the [CDDL or GPL Version 2] license." If you do not indicate a
|
jaroslav@358
|
36 |
* single choice of license, a recipient has the option to distribute
|
jaroslav@358
|
37 |
* your version of this file under either the CDDL, the GPL Version 2 or
|
jaroslav@358
|
38 |
* to extend the choice of license to its licensees as provided above.
|
jaroslav@358
|
39 |
* However, if you add GPL Version 2 code and therefore, elected the GPL
|
jaroslav@358
|
40 |
* Version 2 license, then the option applies only if the new code is
|
jaroslav@358
|
41 |
* made subject to such option by the copyright holder.
|
jaroslav@123
|
42 |
*/
|
jaroslav@123
|
43 |
package net.java.html.boot;
|
jaroslav@123
|
44 |
|
jaroslav@202
|
45 |
import java.io.File;
|
jaroslav@127
|
46 |
import java.io.IOException;
|
jtulach@653
|
47 |
import java.io.InputStream;
|
jaroslav@156
|
48 |
import java.lang.reflect.Method;
|
jtulach@834
|
49 |
import java.net.HttpURLConnection;
|
jtulach@653
|
50 |
import java.net.JarURLConnection;
|
jaroslav@148
|
51 |
import java.net.MalformedURLException;
|
jaroslav@127
|
52 |
import java.net.URL;
|
jtulach@653
|
53 |
import java.net.URLConnection;
|
jtulach@653
|
54 |
import java.security.ProtectionDomain;
|
jaroslav@156
|
55 |
import java.util.Arrays;
|
jaroslav@127
|
56 |
import java.util.Collection;
|
jaroslav@127
|
57 |
import java.util.Enumeration;
|
jtulach@834
|
58 |
import java.util.Locale;
|
jaroslav@127
|
59 |
import java.util.ServiceLoader;
|
jaroslav@574
|
60 |
import java.util.concurrent.Executor;
|
jaroslav@156
|
61 |
import java.util.logging.Level;
|
jaroslav@156
|
62 |
import java.util.logging.Logger;
|
jtulach@569
|
63 |
import net.java.html.BrwsrCtx;
|
jaroslav@166
|
64 |
import net.java.html.js.JavaScriptBody;
|
jtulach@838
|
65 |
import org.netbeans.html.boot.spi.Fn;
|
jtulach@882
|
66 |
import org.netbeans.html.boot.spi.Fn.Presenter;
|
jtulach@838
|
67 |
import org.netbeans.html.context.spi.Contexts;
|
jtulach@886
|
68 |
import org.netbeans.html.context.spi.Contexts.Id;
|
jaroslav@362
|
69 |
import org.netbeans.html.boot.impl.FindResources;
|
jaroslav@362
|
70 |
import org.netbeans.html.boot.impl.FnContext;
|
jaroslav@127
|
71 |
|
jaroslav@166
|
72 |
/** Use this builder to launch your Java/HTML based application. Typical
|
jaroslav@166
|
73 |
* usage in a main method of your application looks like this:
|
jaroslav@166
|
74 |
* <pre>
|
jaroslav@166
|
75 |
*
|
jaroslav@166
|
76 |
* <b>public static void</b> <em>main</em>(String... args) {
|
jtulach@700
|
77 |
* BrowserBuilder.{@link #newBrowser newBrowser()}.
|
jaroslav@166
|
78 |
* {@link #loadClass(java.lang.Class) loadClass(YourMain.class)}.
|
jaroslav@166
|
79 |
* {@link #loadPage(java.lang.String) loadPage("index.html")}.
|
jtulach@836
|
80 |
* {@link #locale(java.util.Locale) locale}({@link Locale#getDefault()}).
|
jaroslav@166
|
81 |
* {@link #invoke(java.lang.String, java.lang.String[]) invoke("initialized", args)}.
|
jaroslav@166
|
82 |
* {@link #showAndWait()};
|
jaroslav@166
|
83 |
* System.exit(0);
|
jaroslav@166
|
84 |
* }
|
jaroslav@166
|
85 |
* </pre>
|
jaroslav@166
|
86 |
* The above will load <code>YourMain</code> class via
|
jaroslav@166
|
87 |
* a special classloader, it will locate an <code>index.html</code> (relative
|
jaroslav@166
|
88 |
* to <code>YourMain</code> class) and show it in a browser window. When the
|
jaroslav@166
|
89 |
* initialization is over, a <b>public static</b> method <em>initialized</em>
|
jaroslav@166
|
90 |
* in <code>YourMain</code> will be called with provided string parameters.
|
jaroslav@166
|
91 |
* <p>
|
jaroslav@166
|
92 |
* This module provides only API for building browsers. To use it properly one
|
jaroslav@166
|
93 |
* also needs an implementation on the classpath of one's application. For example
|
jaroslav@166
|
94 |
* use: <pre>
|
jaroslav@166
|
95 |
* <dependency>
|
jaroslav@361
|
96 |
* <groupId>org.netbeans.html</groupId>
|
jaroslav@361
|
97 |
* <artifactId>net.java.html.boot.fx</artifactId>
|
jaroslav@166
|
98 |
* <scope>runtime</scope>
|
jaroslav@166
|
99 |
* </dependency>
|
jaroslav@166
|
100 |
* </pre>
|
jaroslav@123
|
101 |
*
|
jtulach@790
|
102 |
* @author Jaroslav Tulach
|
jaroslav@123
|
103 |
*/
|
jaroslav@123
|
104 |
public final class BrowserBuilder {
|
jaroslav@156
|
105 |
private static final Logger LOG = Logger.getLogger(BrowserBuilder.class.getName());
|
jaroslav@156
|
106 |
|
jaroslav@127
|
107 |
private String resource;
|
jaroslav@127
|
108 |
private Class<?> clazz;
|
jaroslav@146
|
109 |
private Runnable onLoad;
|
jaroslav@156
|
110 |
private String methodName;
|
jaroslav@156
|
111 |
private String[] methodArgs;
|
jaroslav@288
|
112 |
private final Object[] context;
|
jtulach@771
|
113 |
private ClassLoader loader;
|
jtulach@834
|
114 |
private Locale locale;
|
jaroslav@156
|
115 |
|
jaroslav@288
|
116 |
private BrowserBuilder(Object[] context) {
|
jaroslav@288
|
117 |
this.context = context;
|
jaroslav@123
|
118 |
}
|
jaroslav@166
|
119 |
|
jaroslav@166
|
120 |
/** Entry method to obtain a new browser builder. Follow by calling
|
jaroslav@166
|
121 |
* its instance methods like {@link #loadClass(java.lang.Class)} and
|
jaroslav@166
|
122 |
* {@link #loadPage(java.lang.String)}.
|
jtulach@886
|
123 |
* Since introduction of {@link Id technology identifiers} the
|
jtulach@886
|
124 |
* provided <code>context</code> objects are also passed to the
|
jtulach@886
|
125 |
* {@link BrwsrCtx context} when it is being
|
jtulach@886
|
126 |
* {@link Contexts#newBuilder(java.lang.Object...) created}
|
jtulach@886
|
127 |
* and can influence the selection
|
jtulach@886
|
128 |
* of available technologies
|
jtulach@886
|
129 |
* (like {@link org.netbeans.html.json.spi.Technology},
|
jtulach@886
|
130 |
* {@link org.netbeans.html.json.spi.Transfer} or
|
jtulach@886
|
131 |
* {@link org.netbeans.html.json.spi.WSTransfer}) by name.
|
jaroslav@166
|
132 |
*
|
jaroslav@288
|
133 |
* @param context any instances that should be available to the builder -
|
jaroslav@458
|
134 |
* implementation dependant
|
jaroslav@166
|
135 |
* @return new browser builder
|
jaroslav@166
|
136 |
*/
|
jaroslav@288
|
137 |
public static BrowserBuilder newBrowser(Object... context) {
|
jaroslav@288
|
138 |
return new BrowserBuilder(context);
|
jaroslav@123
|
139 |
}
|
jaroslav@123
|
140 |
|
jaroslav@166
|
141 |
/** The class to load when the browser is initialized. This class
|
jaroslav@166
|
142 |
* is loaded by a special classloader (that supports {@link JavaScriptBody}
|
jaroslav@166
|
143 |
* and co.).
|
jaroslav@166
|
144 |
*
|
jaroslav@166
|
145 |
* @param mainClass the class to load and resolve when the browser is ready
|
jaroslav@166
|
146 |
* @return this builder
|
jaroslav@166
|
147 |
*/
|
jaroslav@127
|
148 |
public BrowserBuilder loadClass(Class<?> mainClass) {
|
jaroslav@127
|
149 |
this.clazz = mainClass;
|
jaroslav@123
|
150 |
return this;
|
jaroslav@123
|
151 |
}
|
jtulach@656
|
152 |
|
jtulach@656
|
153 |
/** Allows one to specify a runnable that should be invoked when a load
|
jtulach@656
|
154 |
* of a page is finished. This method may be used in addition or instead
|
jtulach@656
|
155 |
* of {@link #loadClass(java.lang.Class)} and
|
jtulach@656
|
156 |
* {@link #invoke(java.lang.String, java.lang.String...)} methods.
|
jtulach@656
|
157 |
*
|
jtulach@656
|
158 |
* @param r the code to run when the page is loaded
|
jtulach@656
|
159 |
* @return this builder
|
jtulach@656
|
160 |
* @since 0.8.1
|
jtulach@656
|
161 |
*/
|
jtulach@656
|
162 |
public BrowserBuilder loadFinished(Runnable r) {
|
jtulach@656
|
163 |
this.onLoad = r;
|
jtulach@656
|
164 |
return this;
|
jtulach@656
|
165 |
}
|
jaroslav@156
|
166 |
|
jaroslav@166
|
167 |
/** Page to load into the browser. If the <code>page</code> represents
|
jaroslav@166
|
168 |
* a {@link URL} known to the Java system, the URL is passed to the browser.
|
jaroslav@202
|
169 |
* If system property <code>browser.rootdir</code> is specified, then a
|
jaroslav@202
|
170 |
* file <code>page</code> relative to this directory is used as the URL.
|
jaroslav@202
|
171 |
* If no such file exists, the system seeks for the
|
jaroslav@202
|
172 |
* resource via {@link Class#getResource(java.lang.String)}
|
jaroslav@202
|
173 |
* method (relative to the {@link #loadClass(java.lang.Class) specified class}).
|
jaroslav@202
|
174 |
* If such resource is not found, a file relative to the location JAR
|
jaroslav@202
|
175 |
* that contains the {@link #loadClass(java.lang.Class) main class} is
|
jaroslav@202
|
176 |
* searched for.
|
jtulach@834
|
177 |
* <p>
|
jtulach@834
|
178 |
* The search honors provided {@link #locale}, if specified.
|
jtulach@834
|
179 |
* E.g. it will prefer <code>index_cs.html</code> over <code>index.html</code>
|
jtulach@834
|
180 |
* if the locale is set to <code>cs_CZ</code>.
|
jaroslav@166
|
181 |
*
|
jaroslav@166
|
182 |
* @param page the location (relative, absolute, or URL) of a page to load
|
jtulach@834
|
183 |
* @return this builder
|
jaroslav@166
|
184 |
*/
|
jaroslav@166
|
185 |
public BrowserBuilder loadPage(String page) {
|
jaroslav@166
|
186 |
this.resource = page;
|
jaroslav@166
|
187 |
return this;
|
jaroslav@166
|
188 |
}
|
jaroslav@166
|
189 |
|
jtulach@834
|
190 |
/** Locale to use when searching for an initial {@link #loadPage(java.lang.String) page to load}.
|
jtulach@834
|
191 |
* Localization is best done by providing different versions of the
|
jtulach@834
|
192 |
* initial page with appropriate suffixes (like <code>index_cs.html</code>).
|
jtulach@834
|
193 |
* Then one can call this method with value of {@link Locale#getDefault()}
|
jtulach@834
|
194 |
* to instruct the builder to use the user's current locale.
|
jtulach@834
|
195 |
*
|
jtulach@834
|
196 |
* @param locale the locale to use or <code>null</code> if no suffix search should be performed
|
jtulach@834
|
197 |
* @return this builder
|
jtulach@834
|
198 |
* @since 1.0
|
jtulach@834
|
199 |
*/
|
jtulach@834
|
200 |
public BrowserBuilder locale(Locale locale) {
|
jtulach@834
|
201 |
this.locale = locale;
|
jtulach@834
|
202 |
return this;
|
jtulach@834
|
203 |
}
|
jtulach@834
|
204 |
|
jaroslav@166
|
205 |
/** Specifies callback method to notify the application that the browser is ready.
|
jaroslav@166
|
206 |
* There should be a <b>public static</b> method in the class specified
|
jaroslav@166
|
207 |
* by {@link #loadClass(java.lang.Class)} which takes an array of {@link String}
|
jaroslav@166
|
208 |
* argument. The method is called on the browser dispatch thread one
|
jaroslav@166
|
209 |
* the browser finishes loading of the {@link #loadPage(java.lang.String) HTML page}.
|
jaroslav@166
|
210 |
*
|
jaroslav@166
|
211 |
* @param methodName name of a method to seek for
|
jaroslav@166
|
212 |
* @param args parameters to pass to the method
|
jaroslav@166
|
213 |
* @return this builder
|
jaroslav@166
|
214 |
*/
|
jaroslav@156
|
215 |
public BrowserBuilder invoke(String methodName, String... args) {
|
jaroslav@156
|
216 |
this.methodName = methodName;
|
jaroslav@156
|
217 |
this.methodArgs = args;
|
jaroslav@156
|
218 |
return this;
|
jaroslav@156
|
219 |
}
|
jaroslav@166
|
220 |
|
jtulach@771
|
221 |
/** Loader to use when searching for classes to initialize.
|
jtulach@882
|
222 |
* If specified, this loader is going to be used to load {@link Presenter}
|
jtulach@838
|
223 |
* and {@link Contexts#fillInByProviders(java.lang.Class, org.netbeans.html.context.spi.Contexts.Builder) fill} {@link BrwsrCtx} in.
|
jtulach@771
|
224 |
* Specifying special classloader may be useful in modular systems,
|
jtulach@771
|
225 |
* like OSGi, where one needs to load classes from many otherwise independent
|
jtulach@771
|
226 |
* modules.
|
jtulach@771
|
227 |
*
|
jtulach@771
|
228 |
* @param l the loader to use (or <code>null</code>)
|
jtulach@771
|
229 |
* @return this builder
|
jtulach@771
|
230 |
* @since 0.9
|
jtulach@771
|
231 |
*/
|
jtulach@771
|
232 |
public BrowserBuilder classloader(ClassLoader l) {
|
jtulach@771
|
233 |
this.loader = l;
|
jtulach@771
|
234 |
return this;
|
jtulach@771
|
235 |
}
|
jtulach@771
|
236 |
|
jaroslav@166
|
237 |
/** Shows the browser, loads specified page in and executes the
|
jaroslav@166
|
238 |
* {@link #invoke(java.lang.String, java.lang.String[]) initialization method}.
|
jaroslav@166
|
239 |
* The method returns when the browser is closed.
|
jaroslav@166
|
240 |
*
|
jaroslav@166
|
241 |
* @throws NullPointerException if some of essential parameters (like {@link #loadPage(java.lang.String) page} or
|
jaroslav@166
|
242 |
* {@link #loadClass(java.lang.Class) class} have not been specified
|
jaroslav@166
|
243 |
*/
|
jaroslav@123
|
244 |
public void showAndWait() {
|
jaroslav@146
|
245 |
if (resource == null) {
|
jaroslav@166
|
246 |
throw new NullPointerException("Need to specify resource via loadPage method");
|
jaroslav@146
|
247 |
}
|
jaroslav@146
|
248 |
|
jtulach@656
|
249 |
final Class<?> myCls;
|
jtulach@656
|
250 |
if (clazz != null) {
|
jtulach@656
|
251 |
myCls = clazz;
|
jtulach@656
|
252 |
} else if (onLoad != null) {
|
jtulach@656
|
253 |
myCls = onLoad.getClass();
|
jtulach@656
|
254 |
} else {
|
jtulach@656
|
255 |
throw new NullPointerException("loadClass, neither loadFinished was called!");
|
jtulach@656
|
256 |
}
|
jtulach@834
|
257 |
IOException mal[] = { null };
|
jtulach@834
|
258 |
URL url = findLocalizedResourceURL(resource, locale, mal, myCls);
|
jaroslav@288
|
259 |
|
jaroslav@288
|
260 |
Fn.Presenter dfnr = null;
|
jaroslav@288
|
261 |
for (Object o : context) {
|
jaroslav@288
|
262 |
if (o instanceof Fn.Presenter) {
|
jaroslav@288
|
263 |
dfnr = (Fn.Presenter)o;
|
jaroslav@288
|
264 |
break;
|
jaroslav@288
|
265 |
}
|
jaroslav@288
|
266 |
}
|
jaroslav@127
|
267 |
|
jtulach@771
|
268 |
if (dfnr == null && loader != null) for (Fn.Presenter o : ServiceLoader.load(Fn.Presenter.class, loader)) {
|
jtulach@771
|
269 |
dfnr = o;
|
jtulach@771
|
270 |
break;
|
jtulach@771
|
271 |
}
|
jtulach@771
|
272 |
|
jaroslav@288
|
273 |
if (dfnr == null) for (Fn.Presenter o : ServiceLoader.load(Fn.Presenter.class)) {
|
jaroslav@288
|
274 |
dfnr = o;
|
jaroslav@288
|
275 |
break;
|
jaroslav@288
|
276 |
}
|
jaroslav@288
|
277 |
|
jaroslav@288
|
278 |
if (dfnr == null) {
|
jaroslav@288
|
279 |
throw new IllegalStateException("Can't find any Fn.Presenter");
|
jaroslav@288
|
280 |
}
|
jaroslav@288
|
281 |
|
jtulach@771
|
282 |
final ClassLoader activeLoader;
|
jtulach@771
|
283 |
if (loader != null) {
|
jtulach@897
|
284 |
final URL res = FnContext.isJavaScriptCapable(loader);
|
jtulach@897
|
285 |
if (res != null) {
|
jtulach@897
|
286 |
throw new IllegalStateException("Loader " + loader +
|
jtulach@897
|
287 |
" cannot resolve @JavaScriptBody, because of " + res
|
jtulach@897
|
288 |
);
|
jtulach@771
|
289 |
}
|
jtulach@771
|
290 |
activeLoader = loader;
|
jaroslav@509
|
291 |
} else {
|
jtulach@897
|
292 |
final URL res = FnContext.isJavaScriptCapable(myCls.getClassLoader());
|
jtulach@897
|
293 |
if (res == null) {
|
jtulach@897
|
294 |
activeLoader = myCls.getClassLoader();
|
jtulach@897
|
295 |
} else {
|
jtulach@932
|
296 |
FImpl impl = new FImpl(myCls.getClassLoader());
|
jtulach@932
|
297 |
activeLoader = FnContext.newLoader(res, impl, dfnr, myCls.getClassLoader().getParent());
|
jtulach@932
|
298 |
if (activeLoader == null) {
|
jtulach@897
|
299 |
throw new IllegalStateException("Cannot find asm-5.0.jar classes!");
|
jtulach@897
|
300 |
}
|
jtulach@884
|
301 |
}
|
jaroslav@509
|
302 |
}
|
jtulach@736
|
303 |
|
jtulach@736
|
304 |
final Fn.Presenter dP = dfnr;
|
jaroslav@128
|
305 |
|
jaroslav@288
|
306 |
class OnPageLoad implements Runnable {
|
jaroslav@288
|
307 |
@Override
|
jaroslav@288
|
308 |
public void run() {
|
jaroslav@288
|
309 |
try {
|
jtulach@736
|
310 |
final Fn.Presenter aP = Fn.activePresenter();
|
jtulach@736
|
311 |
final Fn.Presenter currentP = aP != null ? aP : dP;
|
jtulach@736
|
312 |
|
jtulach@771
|
313 |
Thread.currentThread().setContextClassLoader(activeLoader);
|
jtulach@1045
|
314 |
final Class<?> newClazz = onLoad != null ?
|
jtulach@1045
|
315 |
myCls :
|
jtulach@1045
|
316 |
Class.forName(myCls.getName(), true, activeLoader);
|
jtulach@886
|
317 |
Contexts.Builder cb = Contexts.newBuilder(context);
|
jtulach@736
|
318 |
if (!Contexts.fillInByProviders(newClazz, cb)) {
|
jtulach@736
|
319 |
LOG.log(Level.WARNING, "Using empty technology for {0}", newClazz);
|
jtulach@736
|
320 |
}
|
jtulach@736
|
321 |
if (currentP instanceof Executor) {
|
jtulach@736
|
322 |
cb.register(Executor.class, (Executor)currentP, 1000);
|
jtulach@736
|
323 |
}
|
jtulach@736
|
324 |
cb.register(Fn.Presenter.class, currentP, 1000);
|
jtulach@736
|
325 |
BrwsrCtx c = cb.build();
|
jtulach@736
|
326 |
|
jtulach@736
|
327 |
class CallInitMethod implements Runnable {
|
jtulach@736
|
328 |
@Override
|
jtulach@736
|
329 |
public void run() {
|
jtulach@736
|
330 |
Throwable firstError = null;
|
jtulach@736
|
331 |
if (onLoad != null) {
|
jtulach@736
|
332 |
try {
|
jtulach@736
|
333 |
FnContext.currentPresenter(currentP);
|
jtulach@736
|
334 |
onLoad.run();
|
jtulach@736
|
335 |
} catch (Throwable ex) {
|
jtulach@736
|
336 |
firstError = ex;
|
jtulach@736
|
337 |
} finally {
|
jtulach@736
|
338 |
FnContext.currentPresenter(null);
|
jtulach@736
|
339 |
}
|
jtulach@736
|
340 |
}
|
jtulach@736
|
341 |
INIT: if (methodName != null) {
|
jtulach@736
|
342 |
if (methodArgs.length == 0) {
|
jtulach@736
|
343 |
try {
|
jtulach@736
|
344 |
Method m = newClazz.getMethod(methodName);
|
jtulach@736
|
345 |
FnContext.currentPresenter(currentP);
|
jtulach@736
|
346 |
m.invoke(null);
|
jtulach@736
|
347 |
firstError = null;
|
jtulach@736
|
348 |
break INIT;
|
jtulach@736
|
349 |
} catch (Throwable ex) {
|
jtulach@736
|
350 |
firstError = ex;
|
jtulach@736
|
351 |
} finally {
|
jtulach@736
|
352 |
FnContext.currentPresenter(null);
|
jtulach@736
|
353 |
}
|
jtulach@736
|
354 |
}
|
jtulach@736
|
355 |
try {
|
jtulach@736
|
356 |
Method m = newClazz.getMethod(methodName, String[].class);
|
jtulach@736
|
357 |
FnContext.currentPresenter(currentP);
|
jtulach@736
|
358 |
m.invoke(m, (Object) methodArgs);
|
jtulach@736
|
359 |
firstError = null;
|
jtulach@736
|
360 |
} catch (Throwable ex) {
|
jtulach@736
|
361 |
LOG.log(Level.SEVERE, "Can't call " + methodName + " with args " + Arrays.toString(methodArgs), ex);
|
jtulach@736
|
362 |
} finally {
|
jtulach@736
|
363 |
FnContext.currentPresenter(null);
|
jtulach@736
|
364 |
}
|
jtulach@736
|
365 |
}
|
jtulach@736
|
366 |
if (firstError != null) {
|
jtulach@736
|
367 |
LOG.log(Level.SEVERE, "Can't initialize the view", firstError);
|
jtulach@736
|
368 |
}
|
jtulach@569
|
369 |
}
|
jaroslav@288
|
370 |
}
|
jtulach@569
|
371 |
|
jtulach@736
|
372 |
c.execute(new CallInitMethod());
|
jaroslav@288
|
373 |
} catch (ClassNotFoundException ex) {
|
jtulach@656
|
374 |
LOG.log(Level.SEVERE, "Can't load " + myCls.getName(), ex);
|
jaroslav@128
|
375 |
}
|
jaroslav@127
|
376 |
}
|
jaroslav@127
|
377 |
}
|
jaroslav@288
|
378 |
dfnr.displayPage(url, new OnPageLoad());
|
jaroslav@127
|
379 |
}
|
jaroslav@146
|
380 |
|
jtulach@834
|
381 |
private static URL findResourceURL(String resource, String suffix, IOException[] mal, Class<?> relativeTo) {
|
jtulach@834
|
382 |
if (suffix != null) {
|
jtulach@834
|
383 |
int lastDot = resource.lastIndexOf('.');
|
jtulach@834
|
384 |
if (lastDot != -1) {
|
jtulach@834
|
385 |
resource = resource.substring(0, lastDot) + suffix + resource.substring(lastDot);
|
jtulach@834
|
386 |
} else {
|
jtulach@834
|
387 |
resource = resource + suffix;
|
jtulach@834
|
388 |
}
|
jtulach@834
|
389 |
}
|
jtulach@834
|
390 |
|
jtulach@834
|
391 |
URL url = null;
|
jtulach@834
|
392 |
try {
|
jtulach@834
|
393 |
String baseURL = System.getProperty("browser.rootdir"); // NOI18N
|
jtulach@834
|
394 |
if (baseURL != null) {
|
jtulach@834
|
395 |
URL u = new File(baseURL, resource).toURI().toURL();
|
jtulach@834
|
396 |
if (isReal(u)) {
|
jtulach@834
|
397 |
url = u;
|
jtulach@834
|
398 |
}
|
jtulach@834
|
399 |
}
|
jtulach@834
|
400 |
|
jtulach@834
|
401 |
{
|
jtulach@834
|
402 |
URL u = new URL(resource);
|
jtulach@834
|
403 |
if (suffix == null || isReal(u)) {
|
jtulach@834
|
404 |
url = u;
|
jtulach@834
|
405 |
}
|
jtulach@834
|
406 |
return url;
|
jtulach@834
|
407 |
}
|
jtulach@834
|
408 |
} catch (MalformedURLException ex) {
|
jtulach@834
|
409 |
mal[0] = ex;
|
jtulach@834
|
410 |
}
|
jtulach@834
|
411 |
|
jtulach@834
|
412 |
if (url == null) {
|
jtulach@834
|
413 |
url = relativeTo.getResource(resource);
|
jtulach@834
|
414 |
}
|
jtulach@834
|
415 |
if (url == null) {
|
jtulach@834
|
416 |
final ProtectionDomain pd = relativeTo.getProtectionDomain();
|
jtulach@834
|
417 |
if (pd != null && pd.getCodeSource() != null) {
|
jtulach@834
|
418 |
URL jar = pd.getCodeSource().getLocation();
|
jtulach@834
|
419 |
try {
|
jtulach@834
|
420 |
URL u = new URL(jar, resource);
|
jtulach@834
|
421 |
if (isReal(u)) {
|
jtulach@834
|
422 |
url = u;
|
jtulach@834
|
423 |
}
|
jtulach@834
|
424 |
} catch (MalformedURLException ex) {
|
jtulach@834
|
425 |
ex.initCause(mal[0]);
|
jtulach@834
|
426 |
mal[0] = ex;
|
jtulach@834
|
427 |
}
|
jtulach@834
|
428 |
}
|
jtulach@834
|
429 |
}
|
jtulach@834
|
430 |
if (url == null) {
|
jtulach@834
|
431 |
URL res = BrowserBuilder.class.getResource("html4j.txt");
|
jtulach@834
|
432 |
LOG.log(Level.FINE, "Found html4j {0}", res);
|
jtulach@834
|
433 |
if (res != null) {
|
jtulach@834
|
434 |
try {
|
jtulach@834
|
435 |
URLConnection c = res.openConnection();
|
jtulach@834
|
436 |
LOG.log(Level.FINE, "testing : {0}", c);
|
jtulach@834
|
437 |
if (c instanceof JarURLConnection) {
|
jtulach@834
|
438 |
JarURLConnection jc = (JarURLConnection) c;
|
jtulach@834
|
439 |
URL base = jc.getJarFileURL();
|
jtulach@834
|
440 |
for (int i = 0; i < 50; i++) {
|
jtulach@834
|
441 |
URL u = new URL(base, resource);
|
jtulach@834
|
442 |
if (isReal(u)) {
|
jtulach@834
|
443 |
url = u;
|
jtulach@834
|
444 |
break;
|
jtulach@834
|
445 |
}
|
jtulach@834
|
446 |
base = new URL(base, "..");
|
jtulach@834
|
447 |
}
|
jtulach@834
|
448 |
}
|
jtulach@834
|
449 |
} catch (IOException ex) {
|
jtulach@834
|
450 |
mal[0] = ex;
|
jtulach@834
|
451 |
}
|
jtulach@834
|
452 |
}
|
jtulach@834
|
453 |
}
|
jtulach@834
|
454 |
return url;
|
jtulach@834
|
455 |
}
|
jtulach@834
|
456 |
|
jtulach@834
|
457 |
static URL findLocalizedResourceURL(String resource, Locale l, IOException[] mal, Class<?> relativeTo) {
|
jtulach@834
|
458 |
URL url = null;
|
jtulach@834
|
459 |
if (l != null) {
|
jtulach@834
|
460 |
url = findResourceURL(resource, "_" + l.getLanguage() + "_" + l.getCountry(), mal, relativeTo);
|
jtulach@834
|
461 |
if (url != null) {
|
jtulach@834
|
462 |
return url;
|
jtulach@834
|
463 |
}
|
jtulach@834
|
464 |
url = findResourceURL(resource, "_" + l.getLanguage(), mal, relativeTo);
|
jtulach@834
|
465 |
}
|
jtulach@834
|
466 |
if (url != null) {
|
jtulach@834
|
467 |
return url;
|
jtulach@834
|
468 |
}
|
jtulach@834
|
469 |
return findResourceURL(resource, null, mal, relativeTo);
|
jtulach@834
|
470 |
}
|
jtulach@834
|
471 |
|
jtulach@834
|
472 |
private static boolean isReal(URL u) {
|
jtulach@834
|
473 |
try {
|
jtulach@834
|
474 |
URLConnection conn = u.openConnection();
|
jtulach@834
|
475 |
if (conn instanceof HttpURLConnection) {
|
jtulach@834
|
476 |
HttpURLConnection hc = (HttpURLConnection) conn;
|
jtulach@834
|
477 |
hc.setReadTimeout(5000);
|
jtulach@834
|
478 |
if (hc.getResponseCode() >= 300) {
|
jtulach@834
|
479 |
throw new IOException("Wrong code: " + hc.getResponseCode());
|
jtulach@834
|
480 |
}
|
jtulach@834
|
481 |
}
|
jtulach@834
|
482 |
InputStream is = conn.getInputStream();
|
jtulach@834
|
483 |
is.close();
|
jtulach@834
|
484 |
LOG.log(Level.FINE, "found real url: {0}", u);
|
jtulach@834
|
485 |
return true;
|
jtulach@834
|
486 |
} catch (IOException ignore) {
|
jtulach@834
|
487 |
LOG.log(Level.FINE, "Cannot open " + u, ignore);
|
jtulach@834
|
488 |
return false;
|
jtulach@834
|
489 |
}
|
jtulach@834
|
490 |
}
|
jtulach@834
|
491 |
|
jaroslav@128
|
492 |
private static final class FImpl implements FindResources {
|
jaroslav@128
|
493 |
final ClassLoader l;
|
jaroslav@127
|
494 |
|
jaroslav@127
|
495 |
public FImpl(ClassLoader l) {
|
jaroslav@127
|
496 |
this.l = l;
|
jaroslav@127
|
497 |
}
|
jaroslav@127
|
498 |
|
jaroslav@127
|
499 |
@Override
|
jaroslav@127
|
500 |
public void findResources(String path, Collection<? super URL> results, boolean oneIsEnough) {
|
jaroslav@127
|
501 |
if (oneIsEnough) {
|
jaroslav@127
|
502 |
URL u = l.getResource(path);
|
jaroslav@127
|
503 |
if (u != null) {
|
jaroslav@127
|
504 |
results.add(u);
|
jaroslav@127
|
505 |
}
|
jaroslav@127
|
506 |
} else {
|
jaroslav@127
|
507 |
try {
|
jaroslav@127
|
508 |
Enumeration<URL> en = l.getResources(path);
|
jaroslav@127
|
509 |
while (en.hasMoreElements()) {
|
jaroslav@127
|
510 |
results.add(en.nextElement());
|
jaroslav@127
|
511 |
}
|
jaroslav@127
|
512 |
} catch (IOException ex) {
|
jaroslav@127
|
513 |
// no results
|
jaroslav@127
|
514 |
}
|
jaroslav@127
|
515 |
}
|
jaroslav@127
|
516 |
}
|
jaroslav@127
|
517 |
|
jaroslav@123
|
518 |
}
|
jaroslav@123
|
519 |
}
|