├── sample
├── test1.prop
├── test2.prop
├── test1
│ └── com
│ │ └── codemacro
│ │ └── test
│ │ ├── Base.java
│ │ └── A.java
├── test2
│ └── com
│ │ └── codemacro
│ │ └── test
│ │ ├── Base.java
│ │ ├── Export.java
│ │ └── B.java
└── compile.bat
├── kcontainer
├── src
│ ├── main
│ │ ├── resources
│ │ │ └── simplelogger.properties
│ │ └── java
│ │ │ └── com
│ │ │ └── codemacro
│ │ │ └── container
│ │ │ ├── Main.java
│ │ │ ├── SharedClassList.java
│ │ │ ├── BundleConf.java
│ │ │ ├── util
│ │ │ └── UnzipJar.java
│ │ │ ├── Bundle.java
│ │ │ ├── KContainer.java
│ │ │ └── BundleClassLoader.java
│ └── test
│ │ └── java
│ │ └── com
│ │ └── codemacro
│ │ └── container
│ │ └── AppTest.java
└── pom.xml
├── .gitignore
├── kcontainer.interface
├── src
│ ├── main
│ │ └── java
│ │ │ └── com
│ │ │ └── codemacro
│ │ │ └── container
│ │ │ ├── IBundleInitializer.java
│ │ │ └── BundleContext.java
│ └── test
│ │ └── java
│ │ └── com
│ │ └── codemacro
│ │ └── container
│ │ └── AppTest.java
└── pom.xml
├── pom.xml
└── README.md
/sample/test1.prop:
--------------------------------------------------------------------------------
1 | export-class=com.codemacro.test.A
2 |
3 |
--------------------------------------------------------------------------------
/sample/test2.prop:
--------------------------------------------------------------------------------
1 | init=com.codemacro.test.B
2 | export-class=com.codemacro.test.Export
3 |
--------------------------------------------------------------------------------
/kcontainer/src/main/resources/simplelogger.properties:
--------------------------------------------------------------------------------
1 | org.slf4j.simpleLogger.defaultLogLevel=debug
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.swp
2 | *.class
3 | *target*
4 | .classpath
5 | .project
6 | .settings
7 | bundle
8 |
--------------------------------------------------------------------------------
/sample/test1/com/codemacro/test/Base.java:
--------------------------------------------------------------------------------
1 | package com.codemacro.test;
2 |
3 | public class Base {
4 | public void print() {
5 | System.out.println("test1 Base");
6 | }
7 | }
8 |
9 |
--------------------------------------------------------------------------------
/sample/test2/com/codemacro/test/Base.java:
--------------------------------------------------------------------------------
1 | package com.codemacro.test;
2 |
3 | public class Base {
4 | public void print() {
5 | System.out.println("test2 Base");
6 | }
7 | }
8 |
9 |
--------------------------------------------------------------------------------
/sample/test2/com/codemacro/test/Export.java:
--------------------------------------------------------------------------------
1 | package com.codemacro.test;
2 |
3 | public class Export {
4 | public void print() {
5 | System.out.println("test2 Export");
6 | }
7 | }
8 |
9 |
--------------------------------------------------------------------------------
/kcontainer.interface/src/main/java/com/codemacro/container/IBundleInitializer.java:
--------------------------------------------------------------------------------
1 | package com.codemacro.container;
2 |
3 | public interface IBundleInitializer {
4 | void start(BundleContext context);
5 | void stop(BundleContext context);
6 | }
7 |
--------------------------------------------------------------------------------
/kcontainer/src/main/java/com/codemacro/container/Main.java:
--------------------------------------------------------------------------------
1 | package com.codemacro.container;
2 |
3 | // a sample starter
4 | public class Main {
5 |
6 | public static void main(String[] args) {
7 | KContainer container = new KContainer();
8 | container.start();
9 | container.stop();
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/kcontainer.interface/src/main/java/com/codemacro/container/BundleContext.java:
--------------------------------------------------------------------------------
1 | package com.codemacro.container;
2 |
3 | public class BundleContext {
4 | private String name;
5 |
6 | public String getName() {
7 | return name;
8 | }
9 |
10 | public void setName(String name) {
11 | this.name = name;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/sample/test1/com/codemacro/test/A.java:
--------------------------------------------------------------------------------
1 | package com.codemacro.test;
2 |
3 | public class A {
4 | static {
5 | System.out.println("====A====");
6 | System.out.println(A.class.getClassLoader());
7 | Base b = new Base();
8 | b.print();
9 | Export e = new Export();
10 | e.print();
11 | System.out.println("====A====");
12 | }
13 | }
14 |
15 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 | com.codemacro.container
5 | kcontainer-parent
6 | pom
7 | ${k.version}
8 | kcontainer
9 |
10 | kcontainer
11 | kcontainer.interface
12 |
13 |
14 | 0.1.0
15 |
16 |
17 |
--------------------------------------------------------------------------------
/sample/test2/com/codemacro/test/B.java:
--------------------------------------------------------------------------------
1 | package com.codemacro.test;
2 |
3 | import com.codemacro.container.IBundleInitializer;
4 | import com.codemacro.container.BundleContext;
5 |
6 | public class B implements IBundleInitializer {
7 | static {
8 | System.out.println("====B====");
9 | Base b = new Base();
10 | b.print();
11 | System.out.println(B.class.getClassLoader());
12 | System.out.println("====B====");
13 | }
14 |
15 | public void start(BundleContext context) {
16 | System.out.println("B start: " + context.getName());
17 | new A();
18 | }
19 |
20 | public void stop(BundleContext context) {
21 | System.out.println("B stop: " + context.getName());
22 | }
23 | }
24 |
25 |
--------------------------------------------------------------------------------
/kcontainer/src/test/java/com/codemacro/container/AppTest.java:
--------------------------------------------------------------------------------
1 | package com.codemacro.container;
2 |
3 | import junit.framework.Test;
4 | import junit.framework.TestCase;
5 | import junit.framework.TestSuite;
6 |
7 | /**
8 | * Unit test for simple App.
9 | */
10 | public class AppTest
11 | extends TestCase
12 | {
13 | /**
14 | * Create the test case
15 | *
16 | * @param testName name of the test case
17 | */
18 | public AppTest( String testName )
19 | {
20 | super( testName );
21 | }
22 |
23 | /**
24 | * @return the suite of tests being tested
25 | */
26 | public static Test suite()
27 | {
28 | return new TestSuite( AppTest.class );
29 | }
30 |
31 | /**
32 | * Rigourous Test :-)
33 | */
34 | public void testApp()
35 | {
36 | assertTrue( true );
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/kcontainer.interface/src/test/java/com/codemacro/container/AppTest.java:
--------------------------------------------------------------------------------
1 | package com.codemacro.container;
2 |
3 | import junit.framework.Test;
4 | import junit.framework.TestCase;
5 | import junit.framework.TestSuite;
6 |
7 | /**
8 | * Unit test for simple App.
9 | */
10 | public class AppTest
11 | extends TestCase
12 | {
13 | /**
14 | * Create the test case
15 | *
16 | * @param testName name of the test case
17 | */
18 | public AppTest( String testName )
19 | {
20 | super( testName );
21 | }
22 |
23 | /**
24 | * @return the suite of tests being tested
25 | */
26 | public static Test suite()
27 | {
28 | return new TestSuite( AppTest.class );
29 | }
30 |
31 | /**
32 | * Rigourous Test :-)
33 | */
34 | public void testApp()
35 | {
36 | assertTrue( true );
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/kcontainer/src/main/java/com/codemacro/container/SharedClassList.java:
--------------------------------------------------------------------------------
1 | package com.codemacro.container;
2 |
3 | import java.util.concurrent.ConcurrentHashMap;
4 |
5 | import org.slf4j.Logger;
6 | import org.slf4j.LoggerFactory;
7 |
8 | public class SharedClassList {
9 | private static Logger logger = LoggerFactory.getLogger(SharedClassList.class);
10 | private ConcurrentHashMap> classes;
11 |
12 | public SharedClassList() {
13 | classes = new ConcurrentHashMap>();
14 | }
15 |
16 | public void put(String full_name, Class> claz) {
17 | classes.put(full_name, claz);
18 | logger.debug("add shared class {}", full_name);
19 | }
20 |
21 | public Class> get(String full_name) {
22 | return classes.containsKey(full_name) ? classes.get(full_name) : null;
23 | }
24 |
25 | public void clear() {
26 | classes.clear();
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/sample/compile.bat:
--------------------------------------------------------------------------------
1 | @REM test1
2 | javac test1\com\codemacro\test\*.java -d classes\test1 -cp test1\;test2\
3 | del classes\test1\com\codemacro\test\Export.class
4 | mkdir ..\bundle\test1\
5 | mkdir ..\bundle\test1\classes
6 | copy test1.prop ..\bundle\test1\ /Y
7 | xcopy classes\test1 ..\bundle\test1\classes\ /S /Y
8 |
9 | @REM test2
10 | javac test2\com\codemacro\test\*.java -d classes\test2 -cp test1\;test2\;..\kcontainer.interface\src\main\java\
11 | del classes\test2\com\codemacro\container\* /Q
12 | del classes\test2\com\codemacro\test\A.class /Q
13 | jar cf test2.jar -C classes\test2 com
14 | mkdir ..\bundle\test2\
15 | mkdir ..\bundle\test2\lib\
16 | copy test2.prop ..\bundle\test2\ /Y
17 | copy test2.jar ..\bundle\test2\lib\ /Y
18 |
19 | @REM to kcontainer\bundle, test in eclipse
20 | mkdir ..\kcontainer\bundle\test1
21 | xcopy ..\bundle\test1 ..\kcontainer\bundle\test1\ /S /Y
22 | mkdir ..\kcontainer\bundle\test2
23 | xcopy ..\bundle\test2 ..\kcontainer\bundle\test2\ /S /Y
24 |
--------------------------------------------------------------------------------
/kcontainer.interface/pom.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 | kcontainer-parent
5 | com.codemacro.container
6 | ${k.version}
7 |
8 | 4.0.0
9 | com.codemacro.container
10 | kcontainer.interface
11 | jar
12 | 1.0-SNAPSHOT
13 | kcontainer.interface
14 | http://maven.apache.org
15 |
16 |
17 | com.google.guava
18 | guava-collections
19 | r03
20 |
21 |
22 | junit
23 | junit
24 | 3.8.1
25 | test
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | kcontainer is a lightweight container sample.
2 |
3 | 1. import project into eclipse (existing maven project)
4 | 2. cd sample && compile.bat, compile test1 & test2 sample bundle and copy to `kcontainer/bundle` directory, make sure `bundle` directory exists
5 | 3. run kcontainer `Main` in eclipse
6 |
7 | ## Bundle
8 |
9 | ```
10 | .
11 | |-- bundle
12 | |-- test1
13 | |-- test1.prop
14 | |-- lib
15 | | |-- abc.jar (if contains inner jar, unpack it)
16 | | |-- def.jar
17 | |-- classes
18 | |-- lib
19 | ```
20 |
21 | ## Bundle Initializer sample
22 |
23 | ```
24 | public class B implements IBundleInitializer {
25 | static {
26 | System.out.println("====B====");
27 | Base b = new Base();
28 | b.print();
29 | System.out.println(B.class.getClassLoader());
30 | System.out.println("====B====");
31 | }
32 |
33 | public void start(BundleContext context) {
34 | System.out.println("B start: " + context.getName());
35 | new A();
36 | }
37 |
38 | public void stop(BundleContext context) {
39 | System.out.println("B stop: " + context.getName());
40 | }
41 | }
42 | ```
43 |
--------------------------------------------------------------------------------
/kcontainer/pom.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 | kcontainer-parent
5 | com.codemacro.container
6 | ${k.version}
7 |
8 | 4.0.0
9 | com.codemacro.container
10 | kcontainer
11 | jar
12 | 1.0-SNAPSHOT
13 | kcontainer
14 | http://maven.apache.org
15 |
16 |
17 | com.codemacro.container
18 | kcontainer.interface
19 | ${project.version}
20 |
21 |
22 | org.slf4j
23 | slf4j-api
24 | 1.7.12
25 |
26 |
27 | org.slf4j
28 | slf4j-simple
29 | 1.7.5
30 |
31 |
32 | com.google.guava
33 | guava-collections
34 | r03
35 |
36 |
37 | junit
38 | junit
39 | 3.8.1
40 | test
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/kcontainer/src/main/java/com/codemacro/container/BundleConf.java:
--------------------------------------------------------------------------------
1 | package com.codemacro.container;
2 |
3 | import java.io.File;
4 | import java.io.FileInputStream;
5 | import java.io.IOException;
6 | import java.util.List;
7 | import java.util.Properties;
8 |
9 | import com.google.common.base.Function;
10 | import com.google.common.collect.Lists;
11 |
12 | // bundle properties, located at `bundle-name/name.prop`
13 | public class BundleConf {
14 | private static final String KEY_INIT = "init";
15 | private static final String KEY_EXPORT_CLASS = "export-class";
16 | private static final String KEY_IMPORT_CLASS = "import-class";
17 | private List exportClassNames;
18 | private List importClassNames;
19 | private String initClassName;
20 |
21 | public BundleConf(File home) {
22 | String name = home.getName();
23 | File prop = new File(home.getAbsolutePath() + File.separator + name + ".prop");
24 | if (!prop.exists()) {
25 | throw new IllegalArgumentException("bundle prop file not exist");
26 | }
27 | parse(prop);
28 | }
29 |
30 | public List getExportClassNames() {
31 | return exportClassNames;
32 | }
33 |
34 | public List getImportClassNames() {
35 | return importClassNames;
36 | }
37 |
38 | public String getInitClassName() {
39 | return initClassName;
40 | }
41 |
42 | private void parse(File prop) {
43 | Properties properties = new Properties();
44 | try {
45 | properties.load(new FileInputStream(prop));
46 |
47 | } catch (IOException e) {
48 | throw new IllegalArgumentException("parse bundle file failed");
49 | }
50 | this.initClassName = properties.getProperty(KEY_INIT);
51 | this.exportClassNames = parseList(KEY_EXPORT_CLASS, properties);
52 | this.importClassNames = parseList(KEY_IMPORT_CLASS, properties);
53 | }
54 |
55 | private List parseList(String key, Properties properties) {
56 | String val = properties.getProperty(key);
57 | return val == null ? null : Lists.transform(Lists.newArrayList(val.split(";")),
58 | new Function() {
59 | public String apply(String from) {
60 | return from.trim();
61 | }
62 | });
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/kcontainer/src/main/java/com/codemacro/container/util/UnzipJar.java:
--------------------------------------------------------------------------------
1 | package com.codemacro.container.util;
2 |
3 | import java.io.File;
4 | import java.io.FileOutputStream;
5 | import java.io.IOException;
6 | import java.io.InputStream;
7 | import java.io.OutputStream;
8 | import java.util.jar.JarEntry;
9 | import java.util.jar.JarFile;
10 | import java.util.Enumeration;
11 | import java.util.LinkedList;
12 | import java.util.List;
13 |
14 | public class UnzipJar {
15 | private static int DEFAULT_BUFFER_SIZE = 4 * 1024;
16 |
17 | // unzipJar("../tmp/jcm", "../bundle/jcm/lib/jcm.server-0.1.0.jar", ".jar");
18 | public static List unzipJar(String destinationDir, String jarPath, String suffix) throws IOException {
19 | File file = new File(jarPath);
20 | JarFile jar = new JarFile(file);
21 | List results = new LinkedList();
22 | for (Enumeration enums = jar.entries(); enums.hasMoreElements();) {
23 | JarEntry entry = (JarEntry) enums.nextElement();
24 | String fileName = destinationDir + File.separator + entry.getName();
25 | File f = new File(fileName);
26 | if (!entry.isDirectory() && entry.getName().endsWith(suffix)) {
27 | f.getParentFile().mkdirs();
28 | InputStream is = jar.getInputStream(entry);
29 | FileOutputStream fos = new FileOutputStream(f);
30 | try {
31 | copyStream(is, fos);
32 | results.add(f);
33 | } finally {
34 | fos.close();
35 | is.close();
36 | }
37 | }
38 | }
39 | jar.close();
40 | return results;
41 | }
42 |
43 | public static boolean hasEntry(String jarPath, String suffix) {
44 | JarFile jar;
45 | boolean ret = false;
46 | try {
47 | jar = new JarFile(jarPath);
48 | for (Enumeration enums = jar.entries(); enums.hasMoreElements();) {
49 | JarEntry entry = (JarEntry) enums.nextElement();
50 | if (entry.getName().endsWith(suffix)) {
51 | ret = true;
52 | break;
53 | }
54 | }
55 | jar.close();
56 | } catch (IOException e) {
57 | return false;
58 | }
59 | return ret;
60 | }
61 |
62 | private static void copyStream(InputStream is, OutputStream out) throws IOException {
63 | byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
64 | int n = 0;
65 | while (-1 != (n = is.read(buffer))) {
66 | out.write(buffer, 0, n);
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/kcontainer/src/main/java/com/codemacro/container/Bundle.java:
--------------------------------------------------------------------------------
1 | package com.codemacro.container;
2 |
3 | import java.io.File;
4 | import java.util.List;
5 |
6 | import org.slf4j.Logger;
7 | import org.slf4j.LoggerFactory;
8 |
9 | public class Bundle {
10 | private static Logger logger = LoggerFactory.getLogger(Bundle.class);
11 | private ClassLoader claz_loader;
12 | private String name;
13 | private String initClass;
14 | private IBundleInitializer initializer;
15 |
16 | public Bundle(String name, String initClass, ClassLoader loader) {
17 | this.name = name;
18 | this.initClass = initClass;
19 | this.claz_loader = loader;
20 | }
21 |
22 | public void start(BundleContext context) {
23 | if (initClass == null || initClass.isEmpty()) {
24 | logger.info("bundle {} has no init class", name);
25 | return ;
26 | }
27 | try {
28 | Class> claz = claz_loader.loadClass(initClass);
29 | initializer = (IBundleInitializer) claz.newInstance();
30 | initializer.start(context);
31 | logger.info("bundle {} start done", name);
32 | } catch (Exception e) {
33 | logger.warn("bundle {} init failed {}", name, e);
34 | }
35 | }
36 |
37 | public void stop(BundleContext context) {
38 | if (initializer == null) return ;
39 | initializer.stop(context);
40 | logger.info("bundle {} stop done", name);
41 | }
42 |
43 | public String getName() {
44 | return name;
45 | }
46 |
47 | public ClassLoader getClassLoader() {
48 | return claz_loader;
49 | }
50 |
51 | public static Bundle create(File home, String name, SharedClassList sharedClasses,
52 | BundleConf conf) {
53 | BundleClassLoader loader = new BundleClassLoader(home, sharedClasses);
54 | List exports = conf.getExportClassNames();
55 | if (exports != null) {
56 | logger.info("load exported classes for {}", name);
57 | loadExports(loader, sharedClasses, exports);
58 | }
59 | return new Bundle(name, conf.getInitClassName(), loader);
60 | }
61 |
62 | private static void loadExports(ClassLoader loader, SharedClassList sharedClasses,
63 | List exports) {
64 | for (String claz_name: exports) {
65 | try {
66 | Class> claz = loader.loadClass(claz_name);
67 | sharedClasses.put(claz_name, claz);
68 | } catch (ClassNotFoundException e) {
69 | logger.warn("load class {} failed", claz_name);
70 | }
71 | }
72 | }
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/kcontainer/src/main/java/com/codemacro/container/KContainer.java:
--------------------------------------------------------------------------------
1 | package com.codemacro.container;
2 |
3 | import java.io.File;
4 | import java.io.FileFilter;
5 | import java.util.HashMap;
6 | import java.util.Map;
7 | import org.slf4j.Logger;
8 | import org.slf4j.LoggerFactory;
9 |
10 | /*
11 | * kcontainer directory:
12 | * -- lib
13 | * -- bundle
14 | * |-- app
15 | * |-- bundle.prop
16 | * |-- lib
17 | *
18 | */
19 | public class KContainer {
20 | private static Logger logger = LoggerFactory.getLogger(KContainer.class);
21 | private static final String BUNDLE_PATH = "bundle";
22 | private SharedClassList sharedClasses;
23 | private Map bundles;
24 |
25 | public KContainer() {
26 | this.sharedClasses = new SharedClassList();
27 | this.bundles = new HashMap();
28 | }
29 |
30 | public boolean start() {
31 | loadBundles();
32 | startBundles();
33 | return true;
34 | }
35 |
36 | public void stop() {
37 | stopBundles();
38 | sharedClasses.clear();
39 | bundles.clear();
40 | }
41 |
42 | public Map getBundles() {
43 | return bundles;
44 | }
45 |
46 | private void loadBundles() {
47 | File root = new File(BUNDLE_PATH);
48 | logger.info("load bundles...");
49 | File[] bundleDirs = root.listFiles(new FileFilter() {
50 | public boolean accept(File file) {
51 | return file.isDirectory();
52 | }
53 | });
54 | if (bundleDirs == null) {
55 | logger.error("bundle path not exists");
56 | return ;
57 | }
58 | for (File f: bundleDirs) {
59 | Bundle bundle = loadBundle(f);
60 | if (bundle != null) {
61 | logger.info("load bundle [{}] done", bundle.getName());
62 | bundles.put(bundle.getName(), bundle);
63 | }
64 | }
65 | }
66 |
67 | private Bundle loadBundle(File home) {
68 | try {
69 | BundleConf bundle_conf = new BundleConf(home);
70 | Bundle bundle = Bundle.create(home, home.getName(), sharedClasses, bundle_conf);
71 | return bundle;
72 | } catch (IllegalArgumentException e) {
73 | logger.warn("load bundle [{}] failed", home.getName());
74 | return null;
75 | }
76 | }
77 |
78 | private void startBundles() {
79 | logger.info("start all bundles");
80 | for (Bundle bundle : bundles.values()) {
81 | BundleContext context = new BundleContext();
82 | context.setName(bundle.getName());
83 | bundle.start(context);
84 | }
85 | }
86 |
87 | private void stopBundles() {
88 | logger.info("stop all bundles");
89 | for (Bundle bundle : bundles.values()) {
90 | BundleContext context = new BundleContext();
91 | context.setName(bundle.getName());
92 | bundle.stop(context);
93 | }
94 | }
95 |
96 | }
97 |
--------------------------------------------------------------------------------
/kcontainer/src/main/java/com/codemacro/container/BundleClassLoader.java:
--------------------------------------------------------------------------------
1 | package com.codemacro.container;
2 |
3 | import java.io.File;
4 | import java.io.FilenameFilter;
5 | import java.io.IOException;
6 | import java.net.MalformedURLException;
7 | import java.net.URL;
8 | import java.net.URLClassLoader;
9 | import java.util.Collection;
10 | import java.util.List;
11 |
12 | import org.slf4j.Logger;
13 | import org.slf4j.LoggerFactory;
14 |
15 | import com.codemacro.container.util.UnzipJar;
16 | import com.google.common.base.Function;
17 | import com.google.common.base.Predicate;
18 | import com.google.common.collect.Collections2;
19 | import com.google.common.collect.Lists;
20 |
21 | // bundle-name/classes
22 | // bundle-name/lib/*.jar
23 | // bundle-name/lib/*.jar (with inner jars)
24 | public class BundleClassLoader extends URLClassLoader {
25 | private static Logger logger = LoggerFactory.getLogger(BundleClassLoader.class);
26 | private static final String TMP_PATH = new File("./tmp").getAbsolutePath();
27 | private SharedClassList sharedClasses;
28 |
29 | public BundleClassLoader(File home, SharedClassList sharedClasses) {
30 | super(getClassPath(home));
31 | this.sharedClasses = sharedClasses;
32 | }
33 |
34 | @Override
35 | protected Class> findClass(String name) throws ClassNotFoundException {
36 | logger.debug("try find class {}", name);
37 | Class> claz = null;
38 | try {
39 | claz = super.findClass(name);
40 | } catch (ClassNotFoundException e) {
41 | claz = null;
42 | }
43 | if (claz != null) {
44 | logger.debug("load from class path for {}", name);
45 | return claz;
46 | }
47 | claz = sharedClasses.get(name);
48 | if (claz != null) {
49 | logger.debug("load from shared class for {}", name);
50 | return claz;
51 | }
52 | logger.warn("not found class {}", name);
53 | throw new ClassNotFoundException(name);
54 | }
55 |
56 | private static URL[] getClassPath(File home) {
57 | File lib = new File(home.getAbsoluteFile() + "/lib");
58 | File[] jars = lib.listFiles(new FilenameFilter() {
59 | public boolean accept(File file, String name) {
60 | return name.endsWith(".jar");
61 | }
62 | });
63 | Function tran_fn = new Function() {
64 | public URL apply(File file) {
65 | String s = file.isFile() ? "file:/" + file.getAbsolutePath() :
66 | "file:/" + file.getAbsolutePath() + "/";
67 | try {
68 | return new URL(s);
69 | } catch (MalformedURLException e) {
70 | logger.warn("URL exception {}", e);
71 | return null;
72 | }
73 | }
74 | };
75 | Collection col_urls = Lists.newArrayList();
76 | if (jars != null) {
77 | col_urls.addAll(Lists.transform(Lists.newArrayList(jars), tran_fn));
78 | for (File jar: jars) { // add inner jar to class path
79 | if (UnzipJar.hasEntry(jar.getAbsolutePath(), ".jar")) {
80 | List inner_jars = extractInnerJars(home.getName(), jar.getAbsolutePath());
81 | if (inner_jars != null) {
82 | col_urls.addAll(Lists.transform(inner_jars, tran_fn));
83 | }
84 | }
85 | }
86 | }
87 | String classes_path = home.getAbsolutePath() + "/classes/";
88 | File classes = new File(classes_path);
89 | if (classes.exists()) {
90 | col_urls.add(tran_fn.apply(classes));
91 | }
92 |
93 | URL[] urls = new URL[col_urls.size()];
94 | return Lists.newArrayList(Collections2.filter(col_urls, new Predicate() {
95 | public boolean apply(URL url) {
96 | return url != null;
97 | }
98 | })).toArray(urls);
99 | }
100 |
101 | private static List extractInnerJars(String name, String jarFile) {
102 | logger.debug("extract inner jars {}", jarFile);
103 | String dst = TMP_PATH + File.separator + name;
104 | try {
105 | return UnzipJar.unzipJar(dst, jarFile, ".jar");
106 | } catch (IOException e) {
107 | logger.warn("extract jar file {} failed", jarFile);
108 | }
109 | return null;
110 | }
111 |
112 | public static void main(String[] args) throws ClassNotFoundException, IOException, InterruptedException {
113 | File jcm = new File("bundle/jcm");
114 | for (URL u: BundleClassLoader.getClassPath(jcm)) {
115 | System.err.println(u);
116 | }
117 | BundleClassLoader loader = new BundleClassLoader(jcm, null);
118 | System.out.println(loader.loadClass("com.codemacro.jcm.util.Hash"));
119 | System.out.println(loader.loadClass("com.codemacro.jcm.JCMMain"));
120 | loader.close();
121 | }
122 | }
123 |
--------------------------------------------------------------------------------