Skip to content

Commit

Permalink
[DROOLS-729] Android support
Browse files Browse the repository at this point in the history
 * load either default or dex classloaders, depending on environment,
   for generated classes
 * maven plugin for pre-serializing knowledge packages during buildtime
  • Loading branch information
kedzie authored and Petr Siroky committed Jun 21, 2015
1 parent b9568be commit c8e09e2
Show file tree
Hide file tree
Showing 28 changed files with 979 additions and 48 deletions.
Expand Up @@ -196,7 +196,7 @@ public static String getPomProperties(String urlPathToAdd) {
rootPath = IoUtils.asSystemSpecificPath( rootPath, rootPath.lastIndexOf( ':' ) );
}

if ( urlPathToAdd.endsWith( ".jar" ) || urlPathToAdd.endsWith( "/content" ) ) {
if ( urlPathToAdd.endsWith( ".apk" ) || urlPathToAdd.endsWith( ".jar" ) || urlPathToAdd.endsWith( "/content" ) ) {
pomProperties = getPomPropertiesFromZipFile(rootPath);
} else {
pomProperties = getPomPropertiesFromFileSystem(rootPath);
Expand Down
Expand Up @@ -16,6 +16,8 @@

package org.drools.core.base;

import org.drools.core.util.ByteArrayClassLoader;
import org.drools.core.util.ClassUtils;
import org.drools.core.util.asm.ClassFieldInspector;

import java.security.ProtectionDomain;
Expand Down Expand Up @@ -152,7 +154,10 @@ public CacheEntry(ClassLoader parentClassLoader) {
if ( parentClassLoader == null ) {
throw new RuntimeException( "ClassFieldAccessorFactory cannot have a null parent ClassLoader" );
}
this.byteArrayClassLoader = new ByteArrayClassLoader( parentClassLoader );
this.byteArrayClassLoader = ClassUtils.isAndroid() ?
(ByteArrayClassLoader) ClassUtils.instantiateObject(
"org.drools.android.MultiDexClassLoader", null, parentClassLoader) :
new DefaultByteArrayClassLoader( parentClassLoader );
}

public ByteArrayClassLoader getByteArrayClassLoader() {
Expand Down Expand Up @@ -223,8 +228,8 @@ public ClassObjectType getClassObjectType(Class<?> cls,

}

public static class ByteArrayClassLoader extends ClassLoader {
public ByteArrayClassLoader(final ClassLoader parent) {
public static class DefaultByteArrayClassLoader extends ClassLoader implements ByteArrayClassLoader {
public DefaultByteArrayClassLoader(final ClassLoader parent) {
super( parent );
}

Expand Down
Expand Up @@ -16,7 +16,6 @@

package org.drools.core.base;

import org.drools.core.base.ClassFieldAccessorCache.ByteArrayClassLoader;
import org.drools.core.base.ClassFieldAccessorCache.CacheEntry;
import org.drools.core.base.extractors.BaseBooleanClassFieldReader;
import org.drools.core.base.extractors.BaseBooleanClassFieldWriter;
Expand All @@ -41,6 +40,7 @@
import org.drools.core.base.extractors.SelfReferenceClassFieldReader;
import org.drools.core.common.InternalWorkingMemory;
import org.drools.core.util.asm.ClassFieldInspector;
import org.drools.core.util.ByteArrayClassLoader;
import org.mvel2.asm.ClassWriter;
import org.mvel2.asm.Label;
import org.mvel2.asm.MethodVisitor;
Expand Down
@@ -1,5 +1,7 @@
package org.drools.core.common;

import org.drools.core.util.ClassUtils;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
Expand Down Expand Up @@ -130,7 +132,7 @@ protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundE
return cls;
}

private Class<?> internalLoadClass(String name, boolean resolve) throws ClassNotFoundException {
Class<?> internalLoadClass(String name, boolean resolve) throws ClassNotFoundException {
if (CACHE_NON_EXISTING_CLASSES && nonExistingClasses.contains(name)) {
throw dummyCFNE;
}
Expand Down Expand Up @@ -159,7 +161,7 @@ private Class<?> loadType(String name, boolean resolve) throws ClassNotFoundExce
return tryDefineType(name, cnfe);
}

private Class<?> tryDefineType(String name, ClassNotFoundException cnfe) throws ClassNotFoundException {
Class<?> tryDefineType(String name, ClassNotFoundException cnfe) throws ClassNotFoundException {
byte[] bytecode = getBytecode(convertClassToResourcePath(name));
if (bytecode == null) {
if (CACHE_NON_EXISTING_CLASSES) {
Expand All @@ -181,7 +183,7 @@ private Class<?> defineType(String name, byte[] bytecode) {
}

if (typesClassLoader == null) {
typesClassLoader = new InternalTypesClassLoader(this);
typesClassLoader = makeClassLoader();
}
Class<?> clazz = typesClassLoader.defineClass(name, bytecode);
definedTypes.put(name, new ClassBytecode(clazz, bytecode));
Expand Down Expand Up @@ -324,11 +326,23 @@ public void initFrom(ProjectClassLoader other) {
nonExistingClasses.addAll(other.nonExistingClasses);
}

private static class InternalTypesClassLoader extends ClassLoader {
private InternalTypesClassLoader makeClassLoader() {
return ClassUtils.isAndroid() ?
(InternalTypesClassLoader) ClassUtils.instantiateObject(
"org.drools.core.common.DexInternalTypesClassLoader", null, this) :
new DefaultInternalTypesClassLoader( this );
}

interface InternalTypesClassLoader {
Class<?> defineClass(String name, byte[] bytecode);
Class<?> loadType(String name, boolean resolve) throws ClassNotFoundException;
}

private static class DefaultInternalTypesClassLoader extends ClassLoader implements InternalTypesClassLoader {

private final ProjectClassLoader projectClassLoader;

private InternalTypesClassLoader(ProjectClassLoader projectClassLoader) {
private DefaultInternalTypesClassLoader(ProjectClassLoader projectClassLoader) {
super(projectClassLoader.getParent());
this.projectClassLoader = projectClassLoader;
}
Expand Down Expand Up @@ -358,7 +372,7 @@ protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundE
}
}

private Class<?> loadType(String name, boolean resolve) throws ClassNotFoundException {
public Class<?> loadType(String name, boolean resolve) throws ClassNotFoundException {
return super.loadClass(name, resolve);
}
}
Expand Down
Expand Up @@ -21,6 +21,7 @@
import org.drools.core.definitions.rule.impl.RuleImpl;
import org.drools.core.spi.Constraint;
import org.drools.core.spi.Wireable;
import org.drools.core.util.ClassUtils;
import org.drools.core.util.KeyStoreHelper;
import org.drools.core.util.StringUtils;
import org.kie.internal.concurrent.ExecutorProviderFactory;
Expand Down Expand Up @@ -74,7 +75,7 @@ public class JavaDialectRuntimeData

private Map<String, byte[]> store;

private transient PackageClassLoader classLoader;
private transient ClassLoader classLoader;

private transient ClassLoader rootClassLoader;

Expand Down Expand Up @@ -238,8 +239,7 @@ private void checkSignature( final ObjectInput stream,
public void onAdd( DialectRuntimeRegistry registry,
ClassLoader rootClassLoader ) {
this.rootClassLoader = rootClassLoader;
this.classLoader = new PackageClassLoader( this,
this.rootClassLoader );
this.classLoader = makeClassLoader();
}

public void onRemove() {
Expand Down Expand Up @@ -280,18 +280,18 @@ private void wireInParallel(int wireListSize) throws Exception {
}
}

private static void wireAll(PackageClassLoader classLoader, Map<String, Object> invokerLookups, List<String> wireList) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
private static void wireAll(ClassLoader classLoader, Map<String, Object> invokerLookups, List<String> wireList) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
for (String resourceName : wireList) {
wire( classLoader, invokerLookups, convertResourceToClassName( resourceName ) );
}
}

private static class WiringExecutor implements Callable<Boolean> {
private final PackageClassLoader classLoader;
private final ClassLoader classLoader;
private final Map<String, Object> invokerLookups;
private final List<String> wireList;

private WiringExecutor(PackageClassLoader classLoader, Map<String, Object> invokerLookups, List<String> wireList) {
private WiringExecutor(ClassLoader classLoader, Map<String, Object> invokerLookups, List<String> wireList) {
this.classLoader = classLoader;
this.invokerLookups = invokerLookups;
this.wireList = wireList;
Expand Down Expand Up @@ -476,15 +476,15 @@ public void wire( final String className ) throws ClassNotFoundException, Instan
wire(className, getInvokers().get(className));
}

private static void wire( PackageClassLoader classLoader, Map<String, Object> invokerLookups, String className ) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
wire( classLoader, className, invokerLookups.get( className ) );
private static void wire( ClassLoader classLoader, Map<String, Object> invokerLookups, String className ) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
wire( classLoader, className, invokerLookups.get(className) );
}

public void wire( final String className, final Object invoker ) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
wire( classLoader, className, invoker );
}

private static void wire( PackageClassLoader classLoader, String className, Object invoker ) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
private static void wire( ClassLoader classLoader, String className, Object invoker ) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
final Class clazz = classLoader.loadClass( className );

if (clazz != null) {
Expand Down Expand Up @@ -523,8 +523,7 @@ public String[] list() {
*/
public void reload() {
// drops the classLoader and adds a new one
this.classLoader = new PackageClassLoader( this,
this.rootClassLoader );
this.classLoader = makeClassLoader();

// Wire up invokers
try {
Expand Down Expand Up @@ -613,6 +612,13 @@ public void removeClassDefinition( final String className ) {
getClassDefinitions().remove( className );
}

private ClassLoader makeClassLoader() {
return ClassUtils.isAndroid() ?
(ClassLoader) ClassUtils.instantiateObject(
"org.drools.android.DexPackageClassLoader", null, this, this.rootClassLoader)
: new PackageClassLoader( this, this.rootClassLoader );
}

/**
* This is an Internal Drools Class
*/
Expand All @@ -621,7 +627,7 @@ public static class PackageClassLoader extends ClassLoader implements FastClassL
protected JavaDialectRuntimeData store;

private Set<String> existingPackages = new ConcurrentSkipListSet<String>();

public PackageClassLoader( JavaDialectRuntimeData store,
ClassLoader rootClassLoader ) {
super( rootClassLoader );
Expand Down
@@ -1,6 +1,9 @@
package org.drools.core.rule.builder.dialect.asm;

import org.drools.core.base.ClassFieldAccessorCache;
import org.drools.core.base.TypeResolver;
import org.drools.core.util.ByteArrayClassLoader;
import org.drools.core.util.ClassUtils;
import org.mvel2.asm.ClassWriter;
import org.mvel2.asm.MethodVisitor;
import org.mvel2.asm.Type;
Expand Down Expand Up @@ -141,10 +144,16 @@ public byte[] generateBytecode() {
private Class<?> generateClass() {
if (clazz == null) {
byte[] bytecode = generateBytecode();
try {
clazz = (Class<?>) defineClassMethod.invoke(classLoader, className, bytecode, 0, bytecode.length);
} catch (Exception e) {
clazz = new InternalClassLoader(classLoader).defineClass(className, bytecode);
if (ClassUtils.isAndroid()) {
ByteArrayClassLoader cl = (ByteArrayClassLoader)
ClassUtils.instantiateObject("org.drools.android.MultiDexClassLoader", null, classLoader);
clazz = cl.defineClass(className, bytecode, null);
} else {
try {
clazz = (Class<?>) defineClassMethod.invoke(classLoader, className, bytecode, 0, bytecode.length);
} catch (Exception e) {
clazz = new InternalClassLoader(classLoader).defineClass(className, bytecode);
}
}
}
return clazz;
Expand Down
@@ -0,0 +1,24 @@
/*
* Copyright 2015 JBoss Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.drools.core.util;

import java.security.ProtectionDomain;

public interface ByteArrayClassLoader {
Class< ? > defineClass(final String name,
final byte[] bytes,
final ProtectionDomain domain);
}

0 comments on commit c8e09e2

Please sign in to comment.