You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@karaf.apache.org by jb...@apache.org on 2019/11/01 15:30:11 UTC
[karaf] branch karaf-4.2.x updated: [KARAF-6460] Create ClassLoader
that recognize bundle-classpath in case of no OSGi usage e.g.
shell/shell.bat
This is an automated email from the ASF dual-hosted git repository.
jbonofre pushed a commit to branch karaf-4.2.x
in repository https://gitbox.apache.org/repos/asf/karaf.git
The following commit(s) were added to refs/heads/karaf-4.2.x by this push:
new 3c21921 [KARAF-6460] Create ClassLoader that recognize bundle-classpath in case of no OSGi usage e.g. shell/shell.bat
3c21921 is described below
commit 3c21921a2172071d72b8d6c24c64976ee735d33a
Author: Aleksandar Vasilev <a....@seeburger.com>
AuthorDate: Thu Oct 24 09:37:13 2019 +0300
[KARAF-6460] Create ClassLoader that recognize bundle-classpath in case of no OSGi usage e.g. shell/shell.bat
(cherry picked from commit 9d652bcfa0a05a7dec018b7cc842e8f8142363fc)
---
.../impl/console/loader/JarInJarConstants.java | 30 +++++++++++++
.../impl/console/loader/JarInJarStreamHandler.java | 51 ++++++++++++++++++++++
.../impl/console/loader/JarInJarURLConnection.java | 50 +++++++++++++++++++++
.../loader/JarInJarURLStreamHandlerFactory.java | 41 +++++++++++++++++
.../karaf/shell/impl/console/standalone/Main.java | 35 ++++++++++++++-
5 files changed, 206 insertions(+), 1 deletion(-)
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/loader/JarInJarConstants.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/loader/JarInJarConstants.java
new file mode 100644
index 0000000..558c018
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/loader/JarInJarConstants.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.karaf.shell.impl.console.loader;
+
+public interface JarInJarConstants {
+ String REDIRECTED_CLASS_PATH_MANIFEST_NAME = "Bundle-ClassPath";
+ String JAR_INTERNAL_URL_PROTOCOL_WITH_COLON = "jar:jinj:";
+ String JAR_INTERNAL_SEPARATOR = "!/";
+ String INTERNAL_URL_PROTOCOL_WITH_COLON = "jinj:";
+ String INTERNAL_URL_PROTOCOL = "jinj";
+ String PATH_SEPARATOR = "/";
+ String CURRENT_DIR = "./";
+ String JAR_EXTENSION = ".jar";
+}
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/loader/JarInJarStreamHandler.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/loader/JarInJarStreamHandler.java
new file mode 100644
index 0000000..47f5f69
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/loader/JarInJarStreamHandler.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.karaf.shell.impl.console.loader;
+
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.URLStreamHandler;
+
+public class JarInJarStreamHandler extends URLStreamHandler {
+ private ClassLoader classLoader;
+
+ public JarInJarStreamHandler(ClassLoader classLoader) {
+ this.classLoader = classLoader;
+ }
+
+ @Override
+ protected URLConnection openConnection( URL u) throws IOException {
+ return new JarInJarURLConnection(u, classLoader);
+ }
+
+ @Override
+ protected void parseURL(URL url, String spec, int start, int limit) {
+ String file;
+ if (spec.startsWith(JarInJarConstants.INTERNAL_URL_PROTOCOL_WITH_COLON))
+ file = spec.substring(5);
+ else if (url.getFile().equals(JarInJarConstants.CURRENT_DIR))
+ file = spec;
+ else if (url.getFile().endsWith(JarInJarConstants.PATH_SEPARATOR))
+ file = url.getFile() + spec;
+ else
+ file = spec;
+ setURL(url, JarInJarConstants.INTERNAL_URL_PROTOCOL, "", -1, null, null, file, null, null); //$NON-NLS-1$
+ }
+}
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/loader/JarInJarURLConnection.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/loader/JarInJarURLConnection.java
new file mode 100644
index 0000000..d1d56c1
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/loader/JarInJarURLConnection.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.karaf.shell.impl.console.loader;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.URLDecoder;
+import java.nio.charset.StandardCharsets;
+
+public class JarInJarURLConnection extends URLConnection {
+ private ClassLoader classLoader;
+
+ public JarInJarURLConnection( URL url, ClassLoader classLoader) {
+ super(url);
+ this.classLoader= classLoader;
+ }
+
+ @Override
+ public void connect() throws IOException {
+ }
+
+ @Override
+ public InputStream getInputStream() throws IOException {
+ String file= URLDecoder.decode(url.getFile(), StandardCharsets.UTF_8.name() );
+ InputStream result= classLoader.getResourceAsStream(file);
+ if (result == null) {
+ throw new MalformedURLException("Could not open InputStream for URL '" + url + "'");
+ }
+ return result;
+ }
+}
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/loader/JarInJarURLStreamHandlerFactory.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/loader/JarInJarURLStreamHandlerFactory.java
new file mode 100644
index 0000000..8335f5c
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/loader/JarInJarURLStreamHandlerFactory.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.karaf.shell.impl.console.loader;
+
+import java.net.URLStreamHandler;
+import java.net.URLStreamHandlerFactory;
+
+public class JarInJarURLStreamHandlerFactory implements URLStreamHandlerFactory {
+
+ private ClassLoader classLoader;
+ private URLStreamHandlerFactory chainFac;
+
+ public JarInJarURLStreamHandlerFactory(ClassLoader cl) {
+ this.classLoader = cl;
+ }
+
+ @Override
+ public URLStreamHandler createURLStreamHandler( String protocol) {
+ if (JarInJarConstants.INTERNAL_URL_PROTOCOL.equals(protocol))
+ return new JarInJarStreamHandler( classLoader);
+ if (chainFac != null)
+ return chainFac.createURLStreamHandler(protocol);
+ return null;
+ }
+}
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/standalone/Main.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/standalone/Main.java
index 322b986..631e5a8 100644
--- a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/standalone/Main.java
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/standalone/Main.java
@@ -32,7 +32,8 @@ import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
-
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
import org.apache.felix.gogo.runtime.threadio.ThreadIOImpl;
import org.apache.felix.service.threadio.ThreadIO;
import org.apache.karaf.shell.api.action.lifecycle.Manager;
@@ -42,6 +43,8 @@ import org.apache.karaf.shell.api.console.Terminal;
import org.apache.karaf.shell.impl.action.command.ManagerImpl;
import org.apache.karaf.shell.impl.console.JLineTerminal;
import org.apache.karaf.shell.impl.console.SessionFactoryImpl;
+import org.apache.karaf.shell.impl.console.loader.JarInJarConstants;
+import org.apache.karaf.shell.impl.console.loader.JarInJarURLStreamHandlerFactory;
import org.apache.karaf.shell.support.NameScoping;
import org.apache.karaf.shell.support.ShellUtil;
import org.jline.terminal.TerminalBuilder;
@@ -127,6 +130,16 @@ public class Main {
ClassLoader cl = Main.class.getClassLoader();
if (classpath != null) {
List<URL> urls = getFiles(new File(classpath));
+ // Load jars in class path to be able to load jars inside them
+ ClassLoader tmpClassLoader = new URLClassLoader(urls.toArray(new URL[urls.size()]), cl);
+ URL.setURLStreamHandlerFactory(new JarInJarURLStreamHandlerFactory( tmpClassLoader));
+ List<URL> jarsInJars = getJarsInJars(urls);
+ // Create ClassLoader with jars in jars and parent main ClassLoader
+ cl = new URLClassLoader(jarsInJars.toArray(new URL[jarsInJars.size()]), cl);
+ // Load original Jars with jarsInJars ClassLoader as parent.
+ // This is needed cause if you load Class from main jar which depends on class in inner jar.
+ // The loaded class has its class loader and resolve dependant classes in its or parent classloaders
+ // which exclude jarInJar classloader.
cl = new URLClassLoader(urls.toArray(new URL[urls.size()]), cl);
}
@@ -135,6 +148,26 @@ public class Main {
run(sessionFactory, sb.toString(), in, out, err, cl);
}
+ private List<URL> getJarsInJars(List<URL> urls) throws IOException {
+ List<URL> result = new ArrayList<>();
+ for (URL url : urls) {
+ try (JarFile jarFile = new JarFile(url.getFile())) {
+ Manifest manifest = jarFile.getManifest();
+ String embeddedArtifacts = manifest.getMainAttributes().getValue(JarInJarConstants.REDIRECTED_CLASS_PATH_MANIFEST_NAME);
+ if (embeddedArtifacts != null) {
+ String[] artifacts = embeddedArtifacts.split( "," );
+ for ( String artifact : artifacts ) {
+ if (!artifact.endsWith(JarInJarConstants.JAR_EXTENSION )) {
+ continue;
+ }
+ result.add(new URL(JarInJarConstants.JAR_INTERNAL_URL_PROTOCOL_WITH_COLON + artifact + JarInJarConstants.JAR_INTERNAL_SEPARATOR));
+ }
+ }
+ }
+ }
+ return result;
+ }
+
private void run(final SessionFactory sessionFactory, String command, final InputStream in, final PrintStream out, final PrintStream err, ClassLoader cl) throws Exception {
try (org.jline.terminal.Terminal jlineTerminal = TerminalBuilder.terminal()) {