Skip to content

Commit 33b9fa3

Browse files
committed
Fix error in FastByteArrayOutputStream; fix ContinuableClassLoader to avoid load platform classes and own classes (SPI + tools); creating proto of application trampoline
1 parent f08ce56 commit 33b9fa3

File tree

3 files changed

+146
-19
lines changed

3 files changed

+146
-19
lines changed

net.tascalate.javaflow.spi/src/main/java/org/apache/commons/javaflow/spi/FastByteArrayOutputStream.java

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
import java.io.IOException;
1919
import java.io.OutputStream;
2020
import java.io.UnsupportedEncodingException;
21-
import java.util.Arrays;
2221

2322
public class FastByteArrayOutputStream extends OutputStream {
2423

@@ -103,11 +102,17 @@ public void reset() {
103102
* @return the current contents of this output stream, as a byte array.
104103
*/
105104
public byte[] toByteArray() {
106-
return buf.clone();
105+
byte[] result = new byte[count];
106+
System.arraycopy(buf, 0, result, 0, count);
107+
return result;
107108
}
108109

109110
public byte[] unsafeBytes() {
110-
return buf;
111+
if (count == buf.length) {
112+
return buf;
113+
} else {
114+
return toByteArray();
115+
}
111116
}
112117

113118
/**
@@ -186,7 +191,10 @@ private void grow(int minCapacity) {
186191
newCapacity = minCapacity;
187192
if (newCapacity - MAX_ARRAY_SIZE > 0)
188193
newCapacity = hugeCapacity(minCapacity);
189-
buf = Arrays.copyOf(buf, newCapacity);
194+
195+
byte[] newBuf = new byte[newCapacity];
196+
System.arraycopy(buf, 0, newBuf, 0, count);
197+
buf = newBuf;
190198
}
191199

192200
private static int hugeCapacity(int minCapacity) {
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/**
2+
* Original work: copyright 1999-2004 The Apache Software Foundation
3+
* (http://www.apache.org/)
4+
*
5+
* This project is based on the work licensed to the Apache Software
6+
* Foundation (ASF) under one or more contributor license agreements.
7+
* See the NOTICE file distributed with this work for additional
8+
* information regarding copyright ownership.
9+
*
10+
* Modified work: copyright 2013-2019 Valery Silaev (http://vsilaev.com)
11+
*
12+
* Licensed under the Apache License, Version 2.0 (the "License");
13+
* you may not use this file except in compliance with the License.
14+
* You may obtain a copy of the License at
15+
*
16+
* http://www.apache.org/licenses/LICENSE-2.0
17+
*
18+
* Unless required by applicable law or agreed to in writing, software
19+
* distributed under the License is distributed on an "AS IS" BASIS,
20+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21+
* See the License for the specific language governing permissions and
22+
* limitations under the License.
23+
*/
24+
package org.apache.commons.javaflow.tools.runtime;
25+
26+
import java.lang.annotation.Annotation;
27+
import java.lang.reflect.Method;
28+
29+
import org.apache.commons.javaflow.spi.ResourceTransformationFactory;
30+
31+
public final class ApplicationLoader {
32+
private ApplicationLoader() {}
33+
34+
public static boolean trampoline(ResourceTransformationFactory factory, Object source, String...args) {
35+
StackTraceElement ste = new Exception().getStackTrace()[1];
36+
Class<?> clazz;
37+
ClassLoader originalLoader;
38+
39+
if (null == source) {
40+
clazz = null;
41+
originalLoader = Thread.currentThread().getContextClassLoader();
42+
if (null == originalLoader) {
43+
originalLoader = ClassLoader.getSystemClassLoader();
44+
}
45+
} else if (source instanceof Class) {
46+
clazz = (Class<?>)source;
47+
originalLoader = clazz.getClassLoader();
48+
} else {
49+
clazz = source.getClass();
50+
originalLoader = clazz.getClassLoader();
51+
}
52+
53+
if (originalLoader instanceof ContinuableClassLoader)
54+
return false;
55+
56+
try {
57+
try {
58+
Class<?> check = null != clazz ? clazz : originalLoader.loadClass(ste.getClassName());
59+
for (Annotation a : check.getAnnotations()) {
60+
if ("org.apache.commons.javaflow.core.Skip".equals(a.getClass().getName())) {
61+
return false;
62+
}
63+
}
64+
} catch (ClassNotFoundException ex) {
65+
}
66+
67+
ContinuableClassLoader loader = new ContinuableClassLoader.Builder(factory)
68+
.parent(originalLoader)
69+
.parentFirst(false)
70+
//.addLoaderPackageRoot(clazz.getPackage().getName())
71+
.create();
72+
73+
run(loader, ste.getClassName(), ste.getMethodName(), args);
74+
}
75+
catch (RuntimeException ex) {
76+
throw ex;
77+
}
78+
catch (Exception ex) {
79+
throw new RuntimeException(ex);
80+
}
81+
return true;
82+
}
83+
84+
private static void run(ContinuableClassLoader classLoader, String className, String method, String... args) throws Exception {
85+
Class<?> mainClass = classLoader.forceLoadClass(className);
86+
Method mainMethod = mainClass.getMethod(method, String[].class);
87+
mainMethod.invoke(null, new Object[] {args});
88+
}
89+
90+
}

net.tascalate.javaflow.tools.runtime/src/main/java/org/apache/commons/javaflow/tools/runtime/ContinuableClassLoader.java

Lines changed: 44 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ public static class Builder extends AbstractBuilder<ContinuableClassLoader, Buil
182182
* resolver/transformer to perform the byte-code enhancement.
183183
* May not be null.
184184
*/
185-
Builder(ResourceTransformationFactory transformationFactory) {
185+
public Builder(ResourceTransformationFactory transformationFactory) {
186186
super(transformationFactory);
187187
}
188188

@@ -227,6 +227,8 @@ public ContinuableClassLoader create() {
227227

228228
/* The context to be used when loading classes and resources */
229229
protected final AccessControlContext acc;
230+
231+
protected final ClassLoader platformClassLoader;
230232

231233
/**
232234
* Creates a classloader to define classes dynamically.
@@ -292,6 +294,8 @@ public ContinuableClassLoader(ClassLoader parent,
292294
this.isolated = isolated;
293295
this.systemPackages = dotEndingPackageNames(systemPackages);
294296
this.loaderPackages = dotEndingPackageNames(loaderPackages);
297+
298+
this.platformClassLoader = ClassLoader.getSystemClassLoader().getParent();
295299
}
296300

297301
public static Builder builder(ResourceTransformationFactory transformationFactory) {
@@ -346,6 +350,15 @@ private boolean isParentFirst(String resourceName) {
346350
// designated to use a specific loader first
347351
// (this one or the parent one)
348352

353+
if (resourceName.startsWith("org.apache.commons.javaflow.tools.runtime.") ||
354+
resourceName.startsWith("org.apache.commons.javaflow.spi.")) {
355+
return true;
356+
}
357+
358+
// if (resourceName.startsWith("org.apache.commons.javaflow.") && !resourceName.startsWith("org.apache.commons.javaflow.examples.")) {
359+
// return true;
360+
// }
361+
349362
boolean useParentFirst = parentFirst;
350363

351364
for (String packageName : systemPackages) {
@@ -400,24 +413,41 @@ protected Class<?> loadClass(String className, boolean resolve) throws ClassNotF
400413
return theClass;
401414
}
402415

416+
ClassLoader parentClassLoader = getParent();
417+
if (null == parentClassLoader) {
418+
parentClassLoader = platformClassLoader;
419+
}
420+
403421
if (isParentFirst(className)) {
404422
try {
405-
theClass = getParent().loadClass(className);
423+
theClass = parentClassLoader.loadClass(className);
406424
log.debug("Class " + className + " loaded from parent loader " + "(parentFirst)");
407425
} catch (ClassNotFoundException cnfe) {
408426
theClass = findClass(className);
409427
log.debug("Class " + className + " loaded from own loader " + "(parentFirst)");
410428
}
411429
} else {
412-
try {
413-
theClass = findClass(className);
414-
log.debug("Class " + className + " loaded from own loader");
415-
} catch (ClassNotFoundException cnfe) {
416-
if (isolated) {
417-
throw cnfe;
430+
// It's an error to load anything from platform
431+
if (null != platformClassLoader) {
432+
try {
433+
theClass = platformClassLoader.loadClass(className);
434+
log.debug("Class " + className + " is platform class");
435+
} catch (ClassNotFoundException ex) {
436+
log.debug("Class " + className + " is not visible to platform, will try to load on own loader");
437+
}
438+
}
439+
// Not found among platform classes
440+
if (null == theClass) {
441+
try {
442+
theClass = findClass(className);
443+
log.debug("Class " + className + " loaded from own loader");
444+
} catch (ClassNotFoundException cnfe) {
445+
if (isolated) {
446+
throw cnfe;
447+
}
448+
theClass = parentClassLoader.loadClass(className);
449+
log.debug("Class " + className + " loaded from parent loader");
418450
}
419-
theClass = getParent().loadClass(className);
420-
log.debug("Class " + className + " loaded from parent loader");
421451
}
422452
}
423453

@@ -463,7 +493,7 @@ public Class<?> run() {
463493
int i = classNameFromData.lastIndexOf('.');
464494
if (i > 0) {
465495
final String packageName = classNameFromData.substring(0, i);
466-
@SuppressWarnings("deprecation")
496+
@SuppressWarnings("all")
467497
final Package pkg = getPackage(packageName);
468498
if (pkg == null) {
469499
definePackage(packageName, null, null, null, null, null, null, null);
@@ -508,17 +538,16 @@ public Class<?> run() {
508538
* from the stream.
509539
*/
510540
private Class<?> getClassFromStream(InputStream stream, String className) throws IOException, SecurityException {
511-
512-
FastByteArrayOutputStream baos = new FastByteArrayOutputStream();
541+
FastByteArrayOutputStream baos = new FastByteArrayOutputStream(BUFFER_SIZE);
513542
try {
514543

515544
int bytesRead;
516545
byte[] buffer = new byte[BUFFER_SIZE];
517546

518-
while ((bytesRead = stream.read(buffer, 0, BUFFER_SIZE)) != -1) {
547+
while ((bytesRead = stream.read(buffer, 0, BUFFER_SIZE)) > 0) {
519548
baos.write(buffer, 0, bytesRead);
520549
}
521-
550+
522551
byte[] classData = baos.unsafeBytes();
523552
return defineClassFromData(classData, className);
524553

0 commit comments

Comments
 (0)