diff --git a/apache-maven/src/assembly/component.xml b/apache-maven/src/assembly/component.xml
index f8250afe426a..39b6befe8032 100644
--- a/apache-maven/src/assembly/component.xml
+++ b/apache-maven/src/assembly/component.xml
@@ -23,14 +23,26 @@ under the License.
+ * A ClassRealm represents an isolated class loading environment with its own classpath + * and controlled access to classes from other realms through imports. + *
+ * + * @since 4.1.0 + */ +@Experimental +public interface ClassRealm extends Closeable { + + /** + * Returns the unique identifier for this realm. + * + * @return the realm identifier + */ + @Nonnull + String getId(); + + /** + * Returns the class world that contains this realm. + * + * @return the parent class world + */ + @Nonnull + ClassWorld getWorld(); + + /** + * Returns the underlying ClassLoader for this realm. + *+ * This method allows access to the actual ClassLoader implementation + * while maintaining API abstraction. + *
+ * + * @return the underlying ClassLoader + */ + @Nonnull + ClassLoader getClassLoader(); + + /** + * Returns the class loading strategy used by this realm. + * + * @return the strategy + */ + @Nonnull + Strategy getStrategy(); + + /** + * Adds a URL to this realm's classpath. + * + * @param url the URL to add + */ + void addURL(@Nonnull URL url); + + /** + * Returns the URLs in this realm's classpath. + * + * @return array of URLs in the classpath + */ + @Nonnull + URL[] getURLs(); + + /** + * Imports classes from the specified realm for the given package. + * + * @param realmId the identifier of the realm to import from + * @param packageName the package name to import (supports wildcards) + * @throws NoSuchRealmException if the specified realm doesn't exist + */ + void importFrom(@Nonnull String realmId, @Nonnull String packageName) throws NoSuchRealmException; + + /** + * Imports classes from the specified class loader for the given package. + * + * @param classLoader the class loader to import from + * @param packageName the package name to import (supports wildcards) + */ + void importFrom(@Nonnull ClassLoader classLoader, @Nonnull String packageName); + + /** + * Returns the class loader that would handle the specified class name through imports. + * + * @param name the class name + * @return the import class loader, or null if no import matches + */ + @Nullable + ClassLoader getImportClassLoader(@Nonnull String name); + + // Note: getImportRealms method is not included in the API interface + // to avoid conflicts with the existing implementation signature + + /** + * Sets the parent class loader for this realm. + * + * @param parentClassLoader the parent class loader, may be null + */ + void setParentClassLoader(@Nullable ClassLoader parentClassLoader); + + /** + * Returns the parent class loader for this realm. + * + * @return the parent class loader, may be null + */ + @Nullable + ClassLoader getParentClassLoader(); + + // Note: setParentRealm method is not included in the API interface + // to avoid conflicts with the existing implementation signature + + // Note: getParentRealm method is not included in the API interface + // to avoid conflicts with the existing implementation signature + + // Note: createChildRealm method is not included in the API interface + // to avoid conflicts with the existing implementation signature + + /** + * Loads a class from this realm only (not from imports or parent). + * + * @param name the class name + * @return the loaded class, or null if not found + */ + @Nullable + Class> loadClassFromSelf(@Nonnull String name); + + /** + * Loads a class from imported realms/classloaders. + * + * @param name the class name + * @return the loaded class, or null if not found + */ + @Nullable + Class> loadClassFromImport(@Nonnull String name); + + /** + * Loads a class from the parent class loader. + * + * @param name the class name + * @return the loaded class, or null if not found + */ + @Nullable + Class> loadClassFromParent(@Nonnull String name); + + /** + * Loads a resource from this realm only (not from imports or parent). + * + * @param name the resource name + * @return the resource URL, or null if not found + */ + @Nullable + URL loadResourceFromSelf(@Nonnull String name); + + /** + * Loads a resource from imported realms/classloaders. + * + * @param name the resource name + * @return the resource URL, or null if not found + */ + @Nullable + URL loadResourceFromImport(@Nonnull String name); + + /** + * Loads a resource from the parent class loader. + * + * @param name the resource name + * @return the resource URL, or null if not found + */ + @Nullable + URL loadResourceFromParent(@Nonnull String name); + + /** + * Returns whether this realm is loaded as a JPMS module in its own {@link ModuleLayer}. + *+ * When {@code true}, the plugin was loaded via the module path and has its own + * {@link ModuleLayer}. When {@code false}, the plugin is loaded on the classpath + * via a URLClassLoader as usual. + *
+ * + * @return true if this realm has an associated ModuleLayer + * @since 4.1.0 + */ + default boolean isModular() { + return false; + } + + /** + * Returns the {@link ModuleLayer} for this realm, if it was loaded as a JPMS module. + *+ * Returns {@code null} for classpath-based realms. When non-null, the layer contains + * the plugin module and all its dependencies as resolved JPMS modules. + *
+ * + * @return the module layer for this realm, or null for classpath-based realms + * @since 4.1.0 + */ + @Nullable + default ModuleLayer getModuleLayer() { + return null; + } + + /** + * Exports a package from a named JPMS module to this realm's unnamed module, + * making the package's public types accessible to classes loaded by this realm. + * + * @param moduleName the source module name + * @param packageName the package to export + */ + default void addExports(@Nonnull String moduleName, @Nonnull String packageName) {} + + /** + * Opens a package from a named JPMS module to this realm's unnamed module for deep reflection, + * making the package's types accessible via reflection (including non-public members). + * + * @param moduleName the source module name + * @param packageName the package to open + */ + default void addOpens(@Nonnull String moduleName, @Nonnull String packageName) {} + + /** + * Adds a reads edge from a named JPMS module to this realm's unnamed module, + * allowing the named module to access types in this realm. + * + * @param moduleName the source module that should read this realm's unnamed module + */ + default void addReads(@Nonnull String moduleName) {} +} diff --git a/api/maven-api-classworlds/src/main/java/org/apache/maven/api/classworlds/ClassWorld.java b/api/maven-api-classworlds/src/main/java/org/apache/maven/api/classworlds/ClassWorld.java new file mode 100644 index 000000000000..f0f4f876c7ef --- /dev/null +++ b/api/maven-api-classworlds/src/main/java/org/apache/maven/api/classworlds/ClassWorld.java @@ -0,0 +1,117 @@ +/* + * 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.maven.api.classworlds; + +import java.io.Closeable; +import java.util.function.Predicate; + +import org.apache.maven.api.annotations.Experimental; +import org.apache.maven.api.annotations.Nonnull; +import org.apache.maven.api.annotations.Nullable; + +/** + * A collection of {@link ClassRealm}s, indexed by id. + *+ * A ClassWorld provides a container for managing multiple class loading realms, + * each with their own classpath and import/export relationships. + *
+ * + * @since 4.1.0 + */ +@Experimental +public interface ClassWorld extends Closeable { + + /** + * Creates a new class realm with the specified id. + * + * @param id the unique identifier for the realm + * @return the newly created class realm + * @throws DuplicateRealmException if a realm with the same id already exists + */ + @Nonnull + ClassRealm newRealm(@Nonnull String id) throws DuplicateRealmException; + + /** + * Creates a new class realm with the specified id and base class loader. + * + * @param id the unique identifier for the realm + * @param classLoader the base class loader for the realm, may be null + * @return the newly created class realm + * @throws DuplicateRealmException if a realm with the same id already exists + */ + @Nonnull + ClassRealm newRealm(@Nonnull String id, @Nullable ClassLoader classLoader) throws DuplicateRealmException; + + /** + * Creates a new filtered class realm with the specified id, base class loader, and filter. + * + * @param id the unique identifier for the realm + * @param classLoader the base class loader for the realm, may be null + * @param filter the filter to apply to class loading, may be null + * @return the newly created class realm + * @throws DuplicateRealmException if a realm with the same id already exists + */ + @Nonnull + ClassRealm newRealm(@Nonnull String id, @Nullable ClassLoader classLoader, @Nullable Predicate+ * This is the root exception type for all class world operations. + * Specific error conditions are represented by subclasses. + *
+ * + * @since 4.1.0 + */ +@Experimental +public class ClassWorldException extends Exception { + + /** + * The class world associated with this exception. + */ + private final ClassWorld world; + + /** + * Constructs a new ClassWorldException. + * + * @param world the class world associated with this exception + */ + public ClassWorldException(@Nonnull ClassWorld world) { + this.world = world; + } + + /** + * Constructs a new ClassWorldException with the specified detail message. + * + * @param world the class world associated with this exception + * @param message the detail message + */ + public ClassWorldException(@Nonnull ClassWorld world, @Nullable String message) { + super(message); + this.world = world; + } + + /** + * Constructs a new ClassWorldException with the specified detail message and cause. + * + * @param world the class world associated with this exception + * @param message the detail message + * @param cause the cause + */ + public ClassWorldException(@Nonnull ClassWorld world, @Nullable String message, @Nullable Throwable cause) { + super(message, cause); + this.world = world; + } + + /** + * Constructs a new ClassWorldException with the specified cause. + * + * @param world the class world associated with this exception + * @param cause the cause + */ + public ClassWorldException(@Nonnull ClassWorld world, @Nullable Throwable cause) { + super(cause); + this.world = world; + } + + /** + * Returns the class world associated with this exception. + * + * @return the class world + */ + @Nonnull + public ClassWorld getWorld() { + return world; + } +} diff --git a/api/maven-api-classworlds/src/main/java/org/apache/maven/api/classworlds/ClassWorldListener.java b/api/maven-api-classworlds/src/main/java/org/apache/maven/api/classworlds/ClassWorldListener.java new file mode 100644 index 000000000000..5904b23d87d0 --- /dev/null +++ b/api/maven-api-classworlds/src/main/java/org/apache/maven/api/classworlds/ClassWorldListener.java @@ -0,0 +1,49 @@ +/* + * 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.maven.api.classworlds; + +import org.apache.maven.api.annotations.Experimental; +import org.apache.maven.api.annotations.Nonnull; + +/** + * Listener interface for class realm lifecycle events. + *+ * Implementations of this interface can be registered with a {@link ClassWorld} + * to receive notifications when realms are created or disposed. + *
+ * + * @since 4.1.0 + */ +@Experimental +public interface ClassWorldListener { + + /** + * Called when a new class realm is created. + * + * @param realm the newly created realm + */ + void realmCreated(@Nonnull ClassRealm realm); + + /** + * Called when a class realm is disposed. + * + * @param realm the disposed realm + */ + void realmDisposed(@Nonnull ClassRealm realm); +} diff --git a/api/maven-api-classworlds/src/main/java/org/apache/maven/api/classworlds/DuplicateRealmException.java b/api/maven-api-classworlds/src/main/java/org/apache/maven/api/classworlds/DuplicateRealmException.java new file mode 100644 index 000000000000..7d9ca993b288 --- /dev/null +++ b/api/maven-api-classworlds/src/main/java/org/apache/maven/api/classworlds/DuplicateRealmException.java @@ -0,0 +1,58 @@ +/* + * 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.maven.api.classworlds; + +import org.apache.maven.api.annotations.Experimental; +import org.apache.maven.api.annotations.Nonnull; + +/** + * Exception thrown when attempting to create a class realm with an identifier + * that already exists in the class world. + * + * @since 4.1.0 + */ +@Experimental +public class DuplicateRealmException extends ClassWorldException { + + /** + * The duplicate realm identifier. + */ + private final String id; + + /** + * Constructs a new DuplicateRealmException. + * + * @param world the class world + * @param id the duplicate realm identifier + */ + public DuplicateRealmException(@Nonnull ClassWorld world, @Nonnull String id) { + super(world, "Duplicate realm: " + id); + this.id = id; + } + + /** + * Returns the duplicate realm identifier. + * + * @return the realm identifier + */ + @Nonnull + public String getId() { + return id; + } +} diff --git a/api/maven-api-classworlds/src/main/java/org/apache/maven/api/classworlds/NoSuchRealmException.java b/api/maven-api-classworlds/src/main/java/org/apache/maven/api/classworlds/NoSuchRealmException.java new file mode 100644 index 000000000000..223fd8df9db9 --- /dev/null +++ b/api/maven-api-classworlds/src/main/java/org/apache/maven/api/classworlds/NoSuchRealmException.java @@ -0,0 +1,58 @@ +/* + * 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.maven.api.classworlds; + +import org.apache.maven.api.annotations.Experimental; +import org.apache.maven.api.annotations.Nonnull; + +/** + * Exception thrown when attempting to retrieve a class realm with an identifier + * that does not exist in the class world. + * + * @since 4.1.0 + */ +@Experimental +public class NoSuchRealmException extends ClassWorldException { + + /** + * The missing realm identifier. + */ + private final String id; + + /** + * Constructs a new NoSuchRealmException. + * + * @param world the class world + * @param id the missing realm identifier + */ + public NoSuchRealmException(@Nonnull ClassWorld world, @Nonnull String id) { + super(world, "No such realm: " + id); + this.id = id; + } + + /** + * Returns the missing realm identifier. + * + * @return the realm identifier + */ + @Nonnull + public String getId() { + return id; + } +} diff --git a/api/maven-api-classworlds/src/main/java/org/apache/maven/api/classworlds/Strategy.java b/api/maven-api-classworlds/src/main/java/org/apache/maven/api/classworlds/Strategy.java new file mode 100644 index 000000000000..371619f4feda --- /dev/null +++ b/api/maven-api-classworlds/src/main/java/org/apache/maven/api/classworlds/Strategy.java @@ -0,0 +1,77 @@ +/* + * 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.maven.api.classworlds; + +import java.io.IOException; +import java.net.URL; +import java.util.Enumeration; + +import org.apache.maven.api.annotations.Experimental; +import org.apache.maven.api.annotations.Nonnull; +import org.apache.maven.api.annotations.Nullable; + +/** + * A strategy for defining how classes and resources are located in class realms. + *+ * Different strategies can implement different class loading behaviors, such as + * parent-first, child-first, or custom delegation patterns. + *
+ * + * @since 4.1.0 + */ +@Experimental +public interface Strategy { + + /** + * Loads a class using this strategy. + * + * @param name the fully qualified class name + * @return the loaded class + * @throws ClassNotFoundException if the class cannot be found + */ + @Nonnull + Class> loadClass(@Nonnull String name) throws ClassNotFoundException; + + /** + * Finds a resource using this strategy. + * + * @param name the resource name + * @return the resource URL, or null if not found + */ + @Nullable + URL getResource(@Nonnull String name); + + /** + * Finds all resources with the given name using this strategy. + * + * @param name the resource name + * @return an enumeration of resource URLs + * @throws IOException if an I/O error occurs + */ + @Nonnull + Enumeration+ * This package provides the public API for Maven's class loading system, which allows + * for isolated class loading environments (realms) with controlled imports and exports + * between them. + *
+ *+ * Key concepts: + *
+ *+ * This API follows Maven 4 conventions: + *
+ *Note: This is a legacy class provided for backward compatibility with Maven 2. + * New code should avoid using this internal implementation detail.
+ * + * @deprecated This is a legacy internal class. + */ +@Deprecated +public class BytesURLConnection extends URLConnection { + protected final byte[] content; + + protected int offset; + + protected int length; + + public BytesURLConnection(URL url, byte[] content) { + super(url); + this.content = content; + } + + public void connect() {} + + public InputStream getInputStream() { + return new ByteArrayInputStream(content); + } +} diff --git a/impl/maven-classworlds/src/main/java/org/codehaus/classworlds/BytesURLStreamHandler.java b/impl/maven-classworlds/src/main/java/org/codehaus/classworlds/BytesURLStreamHandler.java new file mode 100644 index 000000000000..182c57277452 --- /dev/null +++ b/impl/maven-classworlds/src/main/java/org/codehaus/classworlds/BytesURLStreamHandler.java @@ -0,0 +1,65 @@ +/* + * 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.codehaus.classworlds; + +/* + * Copyright 2001-2010 Codehaus Foundation. + * + * 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. + */ + +import java.net.URL; +import java.net.URLConnection; +import java.net.URLStreamHandler; + +/** + * URLStreamHandler implementation for byte arrays. + * + *Note: This is a legacy class provided for backward compatibility with Maven 2. + * New code should avoid using this internal implementation detail.
+ * + * @author Hani Suleiman (hani@formicary.net) Date: Oct 20, 2003 12:45:18 AM + * @deprecated This is a legacy internal class. + */ +@Deprecated +public class BytesURLStreamHandler extends URLStreamHandler { + final byte[] content; + + int offset; + + int length; + + public BytesURLStreamHandler(byte[] content) { + this.content = content; + } + + public URLConnection openConnection(URL url) { + return new BytesURLConnection(url, content); + } +} diff --git a/impl/maven-classworlds/src/main/java/org/codehaus/classworlds/ClassRealm.java b/impl/maven-classworlds/src/main/java/org/codehaus/classworlds/ClassRealm.java new file mode 100644 index 000000000000..0469a480d33e --- /dev/null +++ b/impl/maven-classworlds/src/main/java/org/codehaus/classworlds/ClassRealm.java @@ -0,0 +1,128 @@ +/* + * 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.codehaus.classworlds; + +/* + +Copyright 2002 (C) The Werken Company. All Rights Reserved. + +Redistribution and use of this software and associated documentation +("Software"), with or without modification, are permitted provided +that the following conditions are met: + +1. Redistributions of source code must retain copyright + statements and notices. Redistributions must also contain a + copy of this document. + +2. Redistributions in binary form must reproduce the + above copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +3. The name "classworlds" must not be used to endorse or promote + products derived from this Software without prior written + permission of The Werken Company. For written permission, + please contact bob@werken.com. + +4. Products derived from this Software may not be called "classworlds" + nor may "classworlds" appear in their names without prior written + permission of The Werken Company. "classworlds" is a registered + trademark of The Werken Company. + +5. Due credit should be given to The Werken Company. + (http://classworlds.werken.com/). + +THIS SOFTWARE IS PROVIDED BY THE WERKEN COMPANY AND CONTRIBUTORS +``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT +NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +THE WERKEN COMPANY OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.Enumeration; + +/** + *Autonomous sub-portion of a ClassWorld.
This class most closed maps to the ClassLoader
+ * role from Java and in facts can provide a ClassLoader
+ * view of itself using {@link #getClassLoader}.
This is a legacy interface from Classworlds 1.x, preserved for binary compatibility. + * The compiled bytecode of {@code org.eclipse.sisu:org.eclipse.sisu.plexus} references this + * interface directly. Removing it breaks all Maven 3+ builds. + * New code should use {@link org.codehaus.plexus.classworlds.realm.ClassRealm}.
+ * + * @author bob mcwhirter + * @author Jason van Zyl + * @deprecated Use {@link org.codehaus.plexus.classworlds.realm.ClassRealm} for new code. + * This interface must remain on the classpath for Sisu compatibility. + */ +@SuppressWarnings("rawtypes") +@Deprecated +public interface ClassRealm { + String getId(); + + ClassWorld getWorld(); + + void importFrom(String realmId, String pkgName) throws NoSuchRealmException; + + void addConstituent(URL constituent); + + ClassRealm locateSourceRealm(String className); + + void setParent(ClassRealm classRealm); + + ClassRealm createChildRealm(String id) throws DuplicateRealmException; + + ClassLoader getClassLoader(); + + ClassRealm getParent(); + + URL[] getConstituents(); + + // ---------------------------------------------------------------------- + // Classloading + // ---------------------------------------------------------------------- + + Class loadClass(String name) throws ClassNotFoundException; + + // ---------------------------------------------------------------------- + // Resource handling + // ---------------------------------------------------------------------- + + URL getResource(String name); + + Enumeration findResources(String name) throws IOException; + + InputStream getResourceAsStream(String name); + + void display(); +} diff --git a/impl/maven-classworlds/src/main/java/org/codehaus/classworlds/ClassRealmAdapter.java b/impl/maven-classworlds/src/main/java/org/codehaus/classworlds/ClassRealmAdapter.java new file mode 100644 index 000000000000..736bc4f4332c --- /dev/null +++ b/impl/maven-classworlds/src/main/java/org/codehaus/classworlds/ClassRealmAdapter.java @@ -0,0 +1,166 @@ +/* + * 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.codehaus.classworlds; + +/* + * Copyright 2001-2010 Codehaus Foundation. + * + * 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. + */ + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.Enumeration; + +/** + * Adapter that wraps a modern {@link org.codehaus.plexus.classworlds.realm.ClassRealm} and exposes + * it as the legacy {@link ClassRealm} interface. + * + *This class is referenced directly by the compiled bytecode of + * {@code org.eclipse.sisu:org.eclipse.sisu.plexus} and must remain on the classpath for + * Maven 3+ to function. Do not remove or rename it. New code should not use this adapter; + * use {@link org.codehaus.plexus.classworlds.realm.ClassRealm} directly.
+ * + * @author Andrew Williams + * @deprecated Legacy adapter retained for Sisu binary compatibility. + */ +@SuppressWarnings({"UnnecessaryLocalVariable", "DeprecatedIsStillUsed", "rawtypes"}) +@Deprecated +public class ClassRealmAdapter implements ClassRealm { + + public static ClassRealmAdapter getInstance(org.codehaus.plexus.classworlds.realm.ClassRealm newRealm) { + ClassRealmAdapter adapter = new ClassRealmAdapter(newRealm); + + return adapter; + } + + private final org.codehaus.plexus.classworlds.realm.ClassRealm realm; + + private ClassRealmAdapter(org.codehaus.plexus.classworlds.realm.ClassRealm newRealm) { + this.realm = newRealm; + } + + public String getId() { + return realm.getId(); + } + + public ClassWorld getWorld() { + return ClassWorldAdapter.getInstance(realm.getWorld()); + } + + public void importFrom(String realmId, String pkgName) throws NoSuchRealmException { + try { + realm.importFrom(realmId, pkgName); + } catch (org.codehaus.plexus.classworlds.realm.NoSuchRealmException e) { + throw new NoSuchRealmException(getWorld(), e.getId()); + } + } + + public void addConstituent(URL constituent) { + realm.addURL(constituent); + } + + public ClassRealm locateSourceRealm(String className) { + ClassLoader importLoader = realm.getImportClassLoader(className); + + if (importLoader instanceof org.codehaus.plexus.classworlds.realm.ClassRealm) { + return ClassRealmAdapter.getInstance((org.codehaus.plexus.classworlds.realm.ClassRealm) importLoader); + } else { + return null; + } + } + + public void setParent(ClassRealm classRealm) { + if (classRealm != null) { + realm.setParentRealm(ClassRealmReverseAdapter.getInstance(classRealm)); + } + } + + public ClassRealm createChildRealm(String id) throws DuplicateRealmException { + try { + return ClassRealmAdapter.getInstance(realm.createChildRealm(id)); + } catch (org.codehaus.plexus.classworlds.realm.DuplicateRealmException e) { + throw new DuplicateRealmException(getWorld(), e.getId()); + } + } + + public ClassLoader getClassLoader() { + return realm; + } + + public ClassRealm getParent() { + return ClassRealmAdapter.getInstance(realm.getParentRealm()); + } + + public ClassRealm getParentRealm() { + return ClassRealmAdapter.getInstance(realm.getParentRealm()); + } + + public URL[] getConstituents() { + return realm.getURLs(); + } + + public Class loadClass(String name) throws ClassNotFoundException { + return realm.loadClass(name); + } + + public URL getResource(String name) { + return realm.getResource(trimLeadingSlash(name)); + } + + public Enumeration findResources(String name) throws IOException { + return realm.findResources(trimLeadingSlash(name)); + } + + public InputStream getResourceAsStream(String name) { + return realm.getResourceAsStream(trimLeadingSlash(name)); + } + + public void display() { + realm.display(); + } + + public boolean equals(Object o) { + if (!(o instanceof ClassRealm)) return false; + + return getId().equals(((ClassRealm) o).getId()); + } + + /** + * Provides backward-compat with the old classworlds which accepted resource names with leading slashes. + */ + private String trimLeadingSlash(String resource) { + if (resource != null && resource.startsWith("/")) { + return resource.substring(1); + } else { + return resource; + } + } +} diff --git a/impl/maven-classworlds/src/main/java/org/codehaus/classworlds/ClassRealmReverseAdapter.java b/impl/maven-classworlds/src/main/java/org/codehaus/classworlds/ClassRealmReverseAdapter.java new file mode 100644 index 000000000000..6019e2dbbe3f --- /dev/null +++ b/impl/maven-classworlds/src/main/java/org/codehaus/classworlds/ClassRealmReverseAdapter.java @@ -0,0 +1,142 @@ +/* + * 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.codehaus.classworlds; + +/* + * Copyright 2001-2010 Codehaus Foundation. + * + * 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. + */ + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.Enumeration; + +/** + * A reverse adapter for ClassRealms. + * + *Note: This is a legacy internal class provided for backward compatibility with Maven 2. + * New code should avoid using this adapter.
+ * + * @author Andrew Williams + * @deprecated This is a legacy internal class. + */ +@SuppressWarnings({"unchecked", "rawtypes"}) +@Deprecated +public class ClassRealmReverseAdapter extends org.codehaus.plexus.classworlds.realm.ClassRealm { + + public static ClassRealmReverseAdapter getInstance(ClassRealm oldRealm) { + return new ClassRealmReverseAdapter(oldRealm); + } + + private final ClassRealm realm; + + private ClassRealmReverseAdapter(ClassRealm oldRealm) { + super(ClassWorldReverseAdapter.getInstance(oldRealm.getWorld()), oldRealm.getId(), oldRealm.getClassLoader()); + this.realm = oldRealm; + } + + public String getId() { + return realm.getId(); + } + + public org.codehaus.plexus.classworlds.ClassWorld getWorld() { + return ClassWorldReverseAdapter.getInstance(realm.getWorld()); + } + + public void importFrom(String realmId, String pkgName) + throws org.codehaus.plexus.classworlds.realm.NoSuchRealmException { + try { + realm.importFrom(realmId, pkgName); + } catch (NoSuchRealmException e) { + throw new org.codehaus.plexus.classworlds.realm.NoSuchRealmException(getWorld(), e.getId()); + } + } + + public void addURL(URL constituent) { + realm.addConstituent(constituent); + } + + public org.codehaus.plexus.classworlds.realm.ClassRealm locateSourceRealm(String className) { + return getInstance(realm.locateSourceRealm(className)); + } + + public void setParentRealm(org.codehaus.plexus.classworlds.realm.ClassRealm classRealm) { + realm.setParent(ClassRealmAdapter.getInstance(classRealm)); + } + + public org.codehaus.plexus.classworlds.realm.ClassRealm createChildRealm(String id) + throws org.codehaus.plexus.classworlds.realm.DuplicateRealmException { + try { + return getInstance(realm.createChildRealm(id)); + } catch (DuplicateRealmException e) { + throw new org.codehaus.plexus.classworlds.realm.DuplicateRealmException(getWorld(), e.getId()); + } + } + + public ClassLoader getClassLoader() { + return realm.getClassLoader(); + } + + public org.codehaus.plexus.classworlds.realm.ClassRealm getParentRealm() { + return getInstance(realm.getParent()); + } + + public URL[] getURLs() { + return realm.getConstituents(); + } + + public Class loadClass(String name) throws ClassNotFoundException { + return realm.loadClass(name); + } + + public URL getResource(String name) { + return realm.getResource(name); + } + + @SuppressWarnings("unchecked") + public Enumeration findResources(String name) throws IOException { + return realm.findResources(name); + } + + public InputStream getResourceAsStream(String name) { + return realm.getResourceAsStream(name); + } + + public void display() { + realm.display(); + } + + public boolean equals(Object o) { + if (!(o instanceof ClassRealm)) return false; + + return getId().equals(((ClassRealm) o).getId()); + } +} diff --git a/impl/maven-classworlds/src/main/java/org/codehaus/classworlds/ClassWorld.java b/impl/maven-classworlds/src/main/java/org/codehaus/classworlds/ClassWorld.java new file mode 100644 index 000000000000..cdc01957987b --- /dev/null +++ b/impl/maven-classworlds/src/main/java/org/codehaus/classworlds/ClassWorld.java @@ -0,0 +1,85 @@ +/* + * 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.codehaus.classworlds; + +/* + * Copyright 2001-2010 Codehaus Foundation. + * + * 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. + */ + +import java.util.Collection; + +/** + * A compatibility wrapper for {@link org.codehaus.plexus.classworlds.ClassWorld} + * provided for legacy code. + * + *Note: This is a legacy class provided for backward compatibility with Maven 2. + * New code should use {@link org.codehaus.plexus.classworlds.ClassWorld}.
+ * + * @author Andrew Williams + * @deprecated Use {@link org.codehaus.plexus.classworlds.ClassWorld} + */ +@SuppressWarnings("rawtypes") +@Deprecated +public class ClassWorld { + private ClassWorldAdapter adapter; + + public ClassWorld(String realmId, ClassLoader classLoader) { + adapter = ClassWorldAdapter.getInstance(new org.codehaus.plexus.classworlds.ClassWorld(realmId, classLoader)); + } + + public ClassWorld() { + adapter = ClassWorldAdapter.getInstance(new org.codehaus.plexus.classworlds.ClassWorld()); + } + + public ClassWorld(boolean ignore) { + /* fake */ + } + + public ClassRealm newRealm(String id) throws DuplicateRealmException { + return adapter.newRealm(id); + } + + public ClassRealm newRealm(String id, ClassLoader classLoader) throws DuplicateRealmException { + return adapter.newRealm(id, classLoader); + } + + public void disposeRealm(String id) throws NoSuchRealmException { + adapter.disposeRealm(id); + } + + public ClassRealm getRealm(String id) throws NoSuchRealmException { + return adapter.getRealm(id); + } + + public Collection getRealms() { + return adapter.getRealms(); + } +} diff --git a/impl/maven-classworlds/src/main/java/org/codehaus/classworlds/ClassWorldAdapter.java b/impl/maven-classworlds/src/main/java/org/codehaus/classworlds/ClassWorldAdapter.java new file mode 100644 index 000000000000..61bb50a37aae --- /dev/null +++ b/impl/maven-classworlds/src/main/java/org/codehaus/classworlds/ClassWorldAdapter.java @@ -0,0 +1,105 @@ +/* + * 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.codehaus.classworlds; + +/* + * Copyright 2001-2010 Codehaus Foundation. + * + * 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. + */ + +import java.util.Collection; +import java.util.Vector; + +/** + * An adapter for ClassWorlds. + * + *Note: This is a legacy internal class provided for backward compatibility with Maven 2. + * New code should avoid using this adapter.
+ * + * @author Andrew Williams + * @deprecated This is a legacy internal class. + */ +@SuppressWarnings("rawtypes") +@Deprecated +public class ClassWorldAdapter extends ClassWorld { + + public static ClassWorldAdapter getInstance(org.codehaus.plexus.classworlds.ClassWorld newWorld) { + return new ClassWorldAdapter(newWorld); + } + + private final org.codehaus.plexus.classworlds.ClassWorld world; + + private ClassWorldAdapter(org.codehaus.plexus.classworlds.ClassWorld newWorld) { + super(false); + this.world = newWorld; + } + + public ClassRealm newRealm(String id) throws DuplicateRealmException { + try { + return ClassRealmAdapter.getInstance(world.newRealm(id)); + } catch (org.codehaus.plexus.classworlds.realm.DuplicateRealmException e) { + throw new DuplicateRealmException(this, e.getId()); + } + } + + public ClassRealm newRealm(String id, ClassLoader classLoader) throws DuplicateRealmException { + try { + return ClassRealmAdapter.getInstance(world.newRealm(id, classLoader)); + } catch (org.codehaus.plexus.classworlds.realm.DuplicateRealmException e) { + throw new DuplicateRealmException(this, e.getId()); + } + } + + public void disposeRealm(String id) throws NoSuchRealmException { + try { + world.disposeRealm(id); + } catch (org.codehaus.plexus.classworlds.realm.NoSuchRealmException e) { + throw new NoSuchRealmException(this, e.getId()); + } + } + + public ClassRealm getRealm(String id) throws NoSuchRealmException { + try { + return ClassRealmAdapter.getInstance(world.getRealm(id)); + } catch (org.codehaus.plexus.classworlds.realm.NoSuchRealmException e) { + throw new NoSuchRealmException(this, e.getId()); + } + } + + public Collection getRealms() { + CollectionClassWorld errors.
+ *
+ * Note: This is a legacy exception provided for backward compatibility with Maven 2. + * New code should use {@link org.codehaus.plexus.classworlds.ClassWorldException}.
+ * + * @author bob mcwhirter + * @deprecated Use {@link org.codehaus.plexus.classworlds.ClassWorldException} + */ +@Deprecated +public class ClassWorldException extends Exception { + // ------------------------------------------------------------ + // Instance members + // ------------------------------------------------------------ + + /** + * The world. + */ + private final ClassWorld world; + + // ------------------------------------------------------------ + // Constructors + // ------------------------------------------------------------ + + /** + * Construct. + * + * @param world The world. + */ + public ClassWorldException(final ClassWorld world) { + this.world = world; + } + + /** + * Construct. + * + * @param world The world. + * @param msg The detail message. + */ + public ClassWorldException(final ClassWorld world, final String msg) { + super(msg); + this.world = world; + } + + // ------------------------------------------------------------ + // Instance methods + // ------------------------------------------------------------ + + /** + * Retrieve the world. + * + * @return The world. + */ + public ClassWorld getWorld() { + return this.world; + } +} diff --git a/impl/maven-classworlds/src/main/java/org/codehaus/classworlds/ClassWorldReverseAdapter.java b/impl/maven-classworlds/src/main/java/org/codehaus/classworlds/ClassWorldReverseAdapter.java new file mode 100644 index 000000000000..8a9543a68b9f --- /dev/null +++ b/impl/maven-classworlds/src/main/java/org/codehaus/classworlds/ClassWorldReverseAdapter.java @@ -0,0 +1,117 @@ +/* + * 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.codehaus.classworlds; + +/* + * Copyright 2001-2010 Codehaus Foundation. + * + * 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. + */ + +import java.util.Collection; +import java.util.HashMap; +import java.util.Vector; + +/** + * A reverse adapter for ClassWorlds. + * + *Note: This is a legacy internal class provided for backward compatibility with Maven 2. + * New code should avoid using this adapter.
+ * + * @author Andrew Williams + * @deprecated This is a legacy internal class. + */ +@SuppressWarnings({"unchecked", "rawtypes"}) +@Deprecated +public class ClassWorldReverseAdapter extends org.codehaus.plexus.classworlds.ClassWorld { + private static final HashMap instances = new HashMap(); + + public static ClassWorldReverseAdapter getInstance(ClassWorld oldWorld) { + if (instances.containsKey(oldWorld)) return (ClassWorldReverseAdapter) instances.get(oldWorld); + + ClassWorldReverseAdapter adapter = new ClassWorldReverseAdapter(oldWorld); + instances.put(oldWorld, adapter); + + return adapter; + } + + private final ClassWorld world; + + private ClassWorldReverseAdapter(ClassWorld newWorld) { + super(); + this.world = newWorld; + } + + public org.codehaus.plexus.classworlds.realm.ClassRealm newRealm(String id) + throws org.codehaus.plexus.classworlds.realm.DuplicateRealmException { + try { + return ClassRealmReverseAdapter.getInstance(world.newRealm(id)); + } catch (DuplicateRealmException e) { + throw new org.codehaus.plexus.classworlds.realm.DuplicateRealmException(this, e.getId()); + } + } + + public org.codehaus.plexus.classworlds.realm.ClassRealm newRealm(String id, ClassLoader classLoader) + throws org.codehaus.plexus.classworlds.realm.DuplicateRealmException { + try { + return ClassRealmReverseAdapter.getInstance(world.newRealm(id, classLoader)); + } catch (DuplicateRealmException e) { + throw new org.codehaus.plexus.classworlds.realm.DuplicateRealmException(this, e.getId()); + } + } + + public void disposeRealm(String id) throws org.codehaus.plexus.classworlds.realm.NoSuchRealmException { + try { + world.disposeRealm(id); + } catch (NoSuchRealmException e) { + throw new org.codehaus.plexus.classworlds.realm.NoSuchRealmException(this, e.getId()); + } + } + + public org.codehaus.plexus.classworlds.realm.ClassRealm getRealm(String id) + throws org.codehaus.plexus.classworlds.realm.NoSuchRealmException { + try { + return ClassRealmReverseAdapter.getInstance(world.getRealm(id)); + } catch (NoSuchRealmException e) { + throw new org.codehaus.plexus.classworlds.realm.NoSuchRealmException(this, e.getId()); + } + } + + public Collection getRealms() { + Collection realms = world.getRealms(); + Vector ret = new Vector(); + + for (Object o : realms) { + ClassRealm realm = (ClassRealm) o; + ret.add(ClassRealmReverseAdapter.getInstance(realm)); + } + + return ret; + } +} diff --git a/impl/maven-classworlds/src/main/java/org/codehaus/classworlds/ConfigurationException.java b/impl/maven-classworlds/src/main/java/org/codehaus/classworlds/ConfigurationException.java new file mode 100644 index 000000000000..97396ba66831 --- /dev/null +++ b/impl/maven-classworlds/src/main/java/org/codehaus/classworlds/ConfigurationException.java @@ -0,0 +1,96 @@ +/* + * 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.codehaus.classworlds; + +/* + +Copyright 2002 (C) The Werken Company. All Rights Reserved. + +Redistribution and use of this software and associated documentation +("Software"), with or without modification, are permitted provided +that the following conditions are met: + +1. Redistributions of source code must retain copyright + statements and notices. Redistributions must also contain a + copy of this document. + +2. Redistributions in binary form must reproduce the + above copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +3. The name "classworlds" must not be used to endorse or promote + products derived from this Software without prior written + permission of The Werken Company. For written permission, + please contact bob@werken.com. + +4. Products derived from this Software may not be called "classworlds" + nor may "classworlds" appear in their names without prior written + permission of The Werken Company. "classworlds" is a registered + trademark of The Werken Company. + +5. Due credit should be given to The Werken Company. + (http://classworlds.werken.com/). + +THIS SOFTWARE IS PROVIDED BY THE WERKEN COMPANY AND CONTRIBUTORS +``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT +NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +THE WERKEN COMPANY OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +/** + * Indicates an error duringLauncher configuration.
+ *
+ * Note: This is a legacy exception provided for backward compatibility with Maven 2. + * New code should use {@link org.codehaus.plexus.classworlds.launcher.ConfigurationException}.
+ * + * @author bob mcwhirter + * @deprecated Use {@link org.codehaus.plexus.classworlds.launcher.ConfigurationException} + */ +@Deprecated +public class ConfigurationException extends Exception { + /** + * Construct. + * + * @param msg The message. + */ + public ConfigurationException(String msg) { + super(msg); + } + + /** + * Construct. + * + * @param msg The message. + * @param lineNo The number of configuraton line where the problem occured. + * @param line The configuration line where the problem occured. + */ + public ConfigurationException(String msg, int lineNo, String line) { + super(msg + " (" + lineNo + "): " + line); + } +} diff --git a/impl/maven-classworlds/src/main/java/org/codehaus/classworlds/Configurator.java b/impl/maven-classworlds/src/main/java/org/codehaus/classworlds/Configurator.java new file mode 100644 index 000000000000..0853c80b5d8c --- /dev/null +++ b/impl/maven-classworlds/src/main/java/org/codehaus/classworlds/Configurator.java @@ -0,0 +1,151 @@ +/* + * 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.codehaus.classworlds; + +/* + * Copyright 2001-2010 Codehaus Foundation. + * + * 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. + */ + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; + +/** + * A compatibility wrapper for {@link org.codehaus.plexus.classworlds.launcher.Configurator} + * provided for legacy code. + * + *Note: This is a legacy class provided for backward compatibility with Maven 2. + * New code should use {@link org.codehaus.plexus.classworlds.launcher.Configurator}.
+ * + * @author Andrew Williams + * @deprecated Use {@link org.codehaus.plexus.classworlds.launcher.Configurator} + */ +@Deprecated +public class Configurator { + private final ConfiguratorAdapter config; + + /** Construct. + * + * @param launcher The launcher to configure. + */ + public Configurator(Launcher launcher) { + config = ConfiguratorAdapter.getInstance( + new org.codehaus.plexus.classworlds.launcher.Configurator(launcher), launcher); + } + + /** Construct. + * + * @param world The classWorld to configure. + */ + public Configurator(ClassWorld world) { + config = ConfiguratorAdapter.getInstance( + new org.codehaus.plexus.classworlds.launcher.Configurator(ClassWorldReverseAdapter.getInstance(world)), + world); + } + + /** set world. + * this setter is provided so you can use the same configurator to configure several "worlds" + * + * @param world The classWorld to configure. + */ + public void setClassWorld(ClassWorld world) { + config.setClassWorld(world); + } + + /** + * Configure from a file. + * + * @param is The config input stream + * @throws IOException If an error occurs reading the config file. + * @throws MalformedURLException If the config file contains invalid URLs. + * @throws ConfigurationException If the config file is corrupt. + * @throws DuplicateRealmException If the config file defines two realms with the same id. + * @throws NoSuchRealmException If the config file defines a main entry point in + * a non-existent realm. + */ + public void configure(InputStream is) + throws IOException, MalformedURLException, ConfigurationException, DuplicateRealmException, + NoSuchRealmException { + config.configureAdapter(is); + } + + /** + * Associate parent realms with their children. + */ + protected void associateRealms() { + config.associateRealms(); + } + + /** + * Load a glob into the specified classloader. + * + * @param line The path configuration line. + * @param realm The realm to populate + * @throws MalformedURLException If the line does not represent + * a valid path element. + * @throws FileNotFoundException If the line does not represent + * a valid path element in the filesystem. + */ + protected void loadGlob(String line, ClassRealm realm) throws MalformedURLException, FileNotFoundException { + loadGlob(line, realm, false); + } + + /** + * Load a glob into the specified classloader. + * + * @param line The path configuration line. + * @param realm The realm to populate + * @param optionally Whether the path is optional or required + * @throws MalformedURLException If the line does not represent + * a valid path element. + * @throws FileNotFoundException If the line does not represent + * a valid path element in the filesystem. + */ + @SuppressWarnings("RedundantThrows") + protected void loadGlob(String line, ClassRealm realm, boolean optionally) + throws MalformedURLException, FileNotFoundException { + config.loadGlob(line, realm, optionally); + } + + /** + * Filter a string for system properties. + * + * @param text The text to filter. + * @return The filtered text. + * @throws ConfigurationException If the property does not + * exist or if there is a syntax error. + */ + @SuppressWarnings("RedundantThrows") + protected String filter(String text) throws ConfigurationException { + return config.filter(text); + } +} diff --git a/impl/maven-classworlds/src/main/java/org/codehaus/classworlds/ConfiguratorAdapter.java b/impl/maven-classworlds/src/main/java/org/codehaus/classworlds/ConfiguratorAdapter.java new file mode 100644 index 000000000000..8cd912c801fe --- /dev/null +++ b/impl/maven-classworlds/src/main/java/org/codehaus/classworlds/ConfiguratorAdapter.java @@ -0,0 +1,92 @@ +/* + * 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.codehaus.classworlds; + +/* + * Copyright 2001-2010 Codehaus Foundation. + * + * 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. + */ + +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; + +/** + * An adapter for Configurators. + * + *Note: This is a legacy internal class provided for backward compatibility with Maven 2. + * New code should avoid using this adapter.
+ * + * @deprecated This is a legacy internal class. + */ +@Deprecated +public class ConfiguratorAdapter extends Configurator { + + public static ConfiguratorAdapter getInstance( + org.codehaus.plexus.classworlds.launcher.Configurator newConfig, Launcher launcher) { + return new ConfiguratorAdapter(newConfig, launcher); + } + + public static ConfiguratorAdapter getInstance( + org.codehaus.plexus.classworlds.launcher.Configurator newConfig, ClassWorld world) { + return new ConfiguratorAdapter(newConfig, world); + } + + private final org.codehaus.plexus.classworlds.launcher.Configurator config; + + private ConfiguratorAdapter(org.codehaus.plexus.classworlds.launcher.Configurator config, Launcher launcher) { + super(launcher); + this.config = config; + } + + private ConfiguratorAdapter(org.codehaus.plexus.classworlds.launcher.Configurator config, ClassWorld world) { + super(world); + this.config = config; + } + + public void associateRealms() { + config.associateRealms(); + } + + @SuppressWarnings("DuplicateThrows") + public void configureAdapter(InputStream is) + throws IOException, MalformedURLException, ConfigurationException, DuplicateRealmException, + NoSuchRealmException { + try { + config.configure(is); + } catch (org.codehaus.plexus.classworlds.launcher.ConfigurationException e) { + throw new ConfigurationException(e.getMessage()); + } catch (org.codehaus.plexus.classworlds.realm.DuplicateRealmException e) { + throw new DuplicateRealmException(ClassWorldAdapter.getInstance(e.getWorld()), e.getId()); + } catch (org.codehaus.plexus.classworlds.realm.NoSuchRealmException e) { + throw new NoSuchRealmException(ClassWorldAdapter.getInstance(e.getWorld()), e.getId()); + } + } +} diff --git a/impl/maven-classworlds/src/main/java/org/codehaus/classworlds/DefaultClassRealm.java b/impl/maven-classworlds/src/main/java/org/codehaus/classworlds/DefaultClassRealm.java new file mode 100644 index 000000000000..1d13a4dee06f --- /dev/null +++ b/impl/maven-classworlds/src/main/java/org/codehaus/classworlds/DefaultClassRealm.java @@ -0,0 +1,162 @@ +/* + * 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.codehaus.classworlds; + +/* + * Copyright 2001-2010 Codehaus Foundation. + * + * 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. + */ + +/** + * A compatibility wrapper for {@link org.codehaus.plexus.classworlds.realm.ClassRealm} + * provided for legacy code. + * + *Note: This is a legacy class provided for backward compatibility with Maven 2. + * New code should use {@link org.codehaus.plexus.classworlds.realm.ClassRealm}.
+ * + * @author Andrew Williams + * @deprecated Use {@link org.codehaus.plexus.classworlds.realm.ClassRealm} + */ +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.Enumeration; + +@SuppressWarnings("rawtypes") +@Deprecated +public class DefaultClassRealm implements ClassRealm { + private final ClassRealmAdapter adapter; + + public DefaultClassRealm(ClassWorld world, String id) { + this(world, id, null); + } + + public DefaultClassRealm(ClassWorld world, String id, ClassLoader foreignClassLoader) { + this.adapter = ClassRealmAdapter.getInstance(new org.codehaus.plexus.classworlds.realm.ClassRealm( + ClassWorldReverseAdapter.getInstance(world), id, foreignClassLoader)); + } + + public URL[] getConstituents() { + return adapter.getConstituents(); + } + + public ClassRealm getParent() { + return adapter.getParentRealm(); + } + + public void setParent(ClassRealm parent) { + adapter.setParent(parent); + } + + public String getId() { + return adapter.getId(); + } + + public ClassWorld getWorld() { + return adapter.getWorld(); + } + + public void importFrom(String realmId, String packageName) throws NoSuchRealmException { + adapter.importFrom(realmId, packageName); + } + + public void addConstituent(URL constituent) { + adapter.addConstituent(constituent); + } + + /** + * Adds a byte[] class definition as a constituent for locating classes. + * Currently uses BytesURLStreamHandler to hold a reference of the byte[] in memory. + * This ensures we have a unifed URL resource model for all constituents. + * The code to cache to disk is commented out - maybe a property to choose which method? + * + * @param constituent class name + * @param b the class definition as a byte[] + * @throws ClassNotFoundException when class couldn't be loaded + */ + public void addConstituent(String constituent, byte[] b) throws ClassNotFoundException { + try { + File path, file; + if (constituent.lastIndexOf('.') != -1) { + path = new File("byteclass/" + + constituent + .substring(0, constituent.lastIndexOf('.') + 1) + .replace('.', File.separatorChar)); + + file = new File(path, constituent.substring(constituent.lastIndexOf('.') + 1) + ".class"); + } else { + path = new File("byteclass/"); + + file = new File(path, constituent + ".class"); + } + + addConstituent(new URL(null, file.toURI().toURL().toExternalForm(), new BytesURLStreamHandler(b))); + } catch (java.io.IOException e) { + throw new ClassNotFoundException("Couldn't load byte stream.", e); + } + } + + public ClassRealm locateSourceRealm(String classname) { + return adapter.locateSourceRealm(classname); + } + + public ClassLoader getClassLoader() { + return adapter.getClassLoader(); + } + + public ClassRealm createChildRealm(String id) throws DuplicateRealmException { + return adapter.createChildRealm(id); + } + + // ---------------------------------------------------------------------- + // ClassLoader API + // ---------------------------------------------------------------------- + + public Class loadClass(String name) throws ClassNotFoundException { + return adapter.loadClass(name); + } + + public URL getResource(String name) { + return adapter.getResource(name); + } + + public InputStream getResourceAsStream(String name) { + return adapter.getResourceAsStream(name); + } + + public Enumeration findResources(String name) throws IOException { + return adapter.findResources(name); + } + + public void display() { + adapter.display(); + } +} diff --git a/impl/maven-classworlds/src/main/java/org/codehaus/classworlds/DuplicateRealmException.java b/impl/maven-classworlds/src/main/java/org/codehaus/classworlds/DuplicateRealmException.java new file mode 100644 index 000000000000..c139554310a3 --- /dev/null +++ b/impl/maven-classworlds/src/main/java/org/codehaus/classworlds/DuplicateRealmException.java @@ -0,0 +1,114 @@ +/* + * 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.codehaus.classworlds; + +/* + +Copyright 2002 (C) The Werken Company. All Rights Reserved. + +Redistribution and use of this software and associated documentation +("Software"), with or without modification, are permitted provided +that the following conditions are met: + +1. Redistributions of source code must retain copyright + statements and notices. Redistributions must also contain a + copy of this document. + +2. Redistributions in binary form must reproduce the + above copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +3. The name "classworlds" must not be used to endorse or promote + products derived from this Software without prior written + permission of The Werken Company. For written permission, + please contact bob@werken.com. + +4. Products derived from this Software may not be called "classworlds" + nor may "classworlds" appear in their names without prior written + permission of The Werken Company. "classworlds" is a registered + trademark of The Werken Company. + +5. Due credit should be given to The Werken Company. + (http://classworlds.werken.com/). + +THIS SOFTWARE IS PROVIDED BY THE WERKEN COMPANY AND CONTRIBUTORS +``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT +NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +THE WERKEN COMPANY OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +/** + * Indicates an attempt to add aClassRealm to a
+ * ClassWorld with a duplicate id.
+ *
+ * Note: This is a legacy exception provided for backward compatibility with Maven 2. + * New code should use {@link org.codehaus.plexus.classworlds.realm.DuplicateRealmException}.
+ * + * @author bob mcwhirter + * @deprecated Use {@link org.codehaus.plexus.classworlds.realm.DuplicateRealmException} + */ +@Deprecated +public class DuplicateRealmException extends ClassWorldException { + // ------------------------------------------------------------ + // Instance members + // ------------------------------------------------------------ + + /** + * The realm id. + */ + private final String id; + + // ------------------------------------------------------------ + // Constructors + // ------------------------------------------------------------ + + /** + * Construct. + * + * @param world The world. + * @param id The realm id. + */ + public DuplicateRealmException(ClassWorld world, String id) { + super(world, id); + this.id = id; + } + + // ------------------------------------------------------------ + // Instance methods + // ------------------------------------------------------------ + + /** + * Retrieve the duplicate realm id. + * + * @return The id. + */ + public String getId() { + return this.id; + } +} diff --git a/impl/maven-classworlds/src/main/java/org/codehaus/classworlds/Launcher.java b/impl/maven-classworlds/src/main/java/org/codehaus/classworlds/Launcher.java new file mode 100644 index 000000000000..d181dbbc9096 --- /dev/null +++ b/impl/maven-classworlds/src/main/java/org/codehaus/classworlds/Launcher.java @@ -0,0 +1,76 @@ +/* + * 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.codehaus.classworlds; + +/* + * Copyright 2001-2010 Codehaus Foundation. + * + * 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. + */ + +/** + * A compatibility wrapper for {@link org.codehaus.plexus.classworlds.launcher.Launcher} + * provided for legacy code. + * + *Note: This is a legacy class provided for backward compatibility with Maven 2. + * New code should use {@link org.codehaus.plexus.classworlds.launcher.Launcher}.
+ * + * @author Andrew Williams + * @deprecated Use {@link org.codehaus.plexus.classworlds.launcher.Launcher} + */ +@Deprecated +public class Launcher extends org.codehaus.plexus.classworlds.launcher.Launcher { + public Launcher() {} + + // ------------------------------------------------------------ + // Class methods + // ------------------------------------------------------------ + + /** + * Launch the launcher from the command line. + * Will exit using System.exit with an exit code of 0 for success, 100 if there was an unknown exception, + * or some other code for an application error. + * + * @param args The application command-line arguments. + */ + public static void main(String[] args) { + org.codehaus.plexus.classworlds.launcher.Launcher.main(args); + } + + /** + * Launch the launcher. + * + * @param args The application command-line arguments. + * @return an integer exit code + * @throws Exception If an error occurs. + */ + public static int mainWithExitCode(String[] args) throws Exception { + return org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(args); + } +} diff --git a/impl/maven-classworlds/src/main/java/org/codehaus/classworlds/NoSuchRealmException.java b/impl/maven-classworlds/src/main/java/org/codehaus/classworlds/NoSuchRealmException.java new file mode 100644 index 000000000000..065cd9cec458 --- /dev/null +++ b/impl/maven-classworlds/src/main/java/org/codehaus/classworlds/NoSuchRealmException.java @@ -0,0 +1,114 @@ +/* + * 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.codehaus.classworlds; + +/* + +Copyright 2002 (C) The Werken Company. All Rights Reserved. + +Redistribution and use of this software and associated documentation +("Software"), with or without modification, are permitted provided +that the following conditions are met: + +1. Redistributions of source code must retain copyright + statements and notices. Redistributions must also contain a + copy of this document. + +2. Redistributions in binary form must reproduce the + above copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +3. The name "classworlds" must not be used to endorse or promote + products derived from this Software without prior written + permission of The Werken Company. For written permission, + please contact bob@werken.com. + +4. Products derived from this Software may not be called "classworlds" + nor may "classworlds" appear in their names without prior written + permission of The Werken Company. "classworlds" is a registered + trademark of The Werken Company. + +5. Due credit should be given to The Werken Company. + (http://classworlds.werken.com/). + +THIS SOFTWARE IS PROVIDED BY THE WERKEN COMPANY AND CONTRIBUTORS +``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT +NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +THE WERKEN COMPANY OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +/** + * Indicates an attempt to retrieve aClassRealm from a
+ * ClassWorld with an invalid id.
+ *
+ * Note: This is a legacy exception provided for backward compatibility with Maven 2. + * New code should use {@link org.codehaus.plexus.classworlds.realm.NoSuchRealmException}.
+ * + * @author bob mcwhirter + * @deprecated Use {@link org.codehaus.plexus.classworlds.realm.NoSuchRealmException} + */ +@Deprecated +public class NoSuchRealmException extends ClassWorldException { + // ------------------------------------------------------------ + // Instance members + // ------------------------------------------------------------ + + /** + * The realm id. + */ + private final String id; + + // ------------------------------------------------------------ + // Constructors + // ------------------------------------------------------------ + + /** + * Construct. + * + * @param world The world. + * @param id The realm id. + */ + public NoSuchRealmException(ClassWorld world, String id) { + super(world, id); + this.id = id; + } + + // ------------------------------------------------------------ + // Instance methods + // ------------------------------------------------------------ + + /** + * Retrieve the invalid realm id. + * + * @return The id. + */ + public String getId() { + return this.id; + } +} diff --git a/impl/maven-classworlds/src/main/java/org/codehaus/classworlds/package-info.java b/impl/maven-classworlds/src/main/java/org/codehaus/classworlds/package-info.java new file mode 100644 index 000000000000..e94806c4c752 --- /dev/null +++ b/impl/maven-classworlds/src/main/java/org/codehaus/classworlds/package-info.java @@ -0,0 +1,37 @@ +/* + * 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. + */ +/** + * Legacy Classworlds 1.x API, preserved for binary compatibility with Eclipse Sisu. + * + *This package has been deprecated since version 2.5.2 (2014). New code should use + * {@code org.codehaus.plexus.classworlds} instead.
+ * + *Do not remove this package. The compiled bytecode of + * {@code org.eclipse.sisu:org.eclipse.sisu.plexus} references {@link ClassRealm}, + * {@link ClassRealmAdapter}, and {@link ClassRealmReverseAdapter} from this package. + * Removing them causes {@code ClassNotFoundException} at runtime for any application + * using Sisu, including all Maven 3+ builds.
+ * + *PR #141 removed this package and had to be reverted immediately (commit 223416e). + * See {@code COMPATIBILITY.md} for details on what Sisu references and what preconditions + * must be satisfied before any future removal.
+ * + * @deprecated Use {@code org.codehaus.plexus.classworlds} for new code. + */ +package org.codehaus.classworlds; diff --git a/impl/maven-classworlds/src/main/java/org/codehaus/plexus/classworlds/ClassWorld.java b/impl/maven-classworlds/src/main/java/org/codehaus/plexus/classworlds/ClassWorld.java new file mode 100644 index 000000000000..27ebb12cb2bf --- /dev/null +++ b/impl/maven-classworlds/src/main/java/org/codehaus/plexus/classworlds/ClassWorld.java @@ -0,0 +1,303 @@ +/* + * 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.codehaus.plexus.classworlds; + +/* + * Copyright 2001-2006 Codehaus Foundation. + * + * 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. + */ + +import java.io.Closeable; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; + +import org.codehaus.plexus.classworlds.realm.ClassRealm; +import org.codehaus.plexus.classworlds.realm.DuplicateRealmException; +import org.codehaus.plexus.classworlds.realm.FilteredClassRealm; +import org.codehaus.plexus.classworlds.realm.NoSuchRealmException; + +/** + * A collection ofClassRealms, indexed by id.
+ *
+ * @author bob mcwhirter
+ */
+public class ClassWorld implements org.apache.maven.api.classworlds.ClassWorld, Closeable {
+ private Mapnull.
+ * @param classLoader The base class loader for this realm, may be null to use the bootstrap class
+ * loader.
+ * @param filter a predicate to apply to each resource name to determine if it should be loaded through this class loader
+ * @return the created class realm
+ * @throws DuplicateRealmException in case a realm with the given id does already exist
+ * @since 2.7.0
+ * @see FilteredClassRealm
+ */
+ public synchronized ClassRealm newRealm(String id, ClassLoader classLoader, PredicateClassWorld errors.
+ *
+ * @author bob mcwhirter
+ */
+public class ClassWorldException extends org.apache.maven.api.classworlds.ClassWorldException {
+ // ------------------------------------------------------------
+ // Instance members
+ // ------------------------------------------------------------
+
+ /**
+ * The world.
+ */
+ private ClassWorld world;
+
+ // ------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------
+
+ /**
+ * Construct.
+ *
+ * @param world The world.
+ */
+ public ClassWorldException(final ClassWorld world) {
+ super(world);
+ this.world = world;
+ }
+
+ /**
+ * Construct.
+ *
+ * @param world The world.
+ * @param msg The detail message.
+ */
+ public ClassWorldException(final ClassWorld world, final String msg) {
+ super(world, msg);
+ this.world = world;
+ }
+
+ // ------------------------------------------------------------
+ // Instance methods
+ // ------------------------------------------------------------
+
+ /**
+ * Retrieve the world.
+ *
+ * @return The world.
+ */
+ public ClassWorld getWorld() {
+ return this.world;
+ }
+}
diff --git a/impl/maven-classworlds/src/main/java/org/codehaus/plexus/classworlds/ClassWorldListener.java b/impl/maven-classworlds/src/main/java/org/codehaus/plexus/classworlds/ClassWorldListener.java
new file mode 100644
index 000000000000..7e27e279d53b
--- /dev/null
+++ b/impl/maven-classworlds/src/main/java/org/codehaus/plexus/classworlds/ClassWorldListener.java
@@ -0,0 +1,43 @@
+/*
+ * 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.codehaus.plexus.classworlds;
+
+/*
+ * Copyright 2001-2006 Codehaus Foundation.
+ *
+ * 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.
+ */
+
+import org.codehaus.plexus.classworlds.realm.ClassRealm;
+
+public interface ClassWorldListener extends org.apache.maven.api.classworlds.ClassWorldListener {
+ void realmCreated(ClassRealm realm);
+
+ void realmDisposed(ClassRealm realm);
+}
diff --git a/impl/maven-classworlds/src/main/java/org/codehaus/plexus/classworlds/UrlUtils.java b/impl/maven-classworlds/src/main/java/org/codehaus/plexus/classworlds/UrlUtils.java
new file mode 100644
index 000000000000..00d0e2c2a9e2
--- /dev/null
+++ b/impl/maven-classworlds/src/main/java/org/codehaus/plexus/classworlds/UrlUtils.java
@@ -0,0 +1,74 @@
+/*
+ * 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.codehaus.plexus.classworlds;
+
+/*
+ * Copyright 2001-2006 Codehaus Foundation.
+ *
+ * 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.
+ */
+
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author Jason van Zyl
+ */
+public class UrlUtils {
+ public static String normalizeUrlPath(String name) {
+ if (name.startsWith("/")) {
+ name = name.substring(1);
+ }
+
+ // Looking for org/codehaus/werkflow/personality/basic/../common/core-idioms.xml
+ // | i |
+ // +-------+ remove
+ //
+ int i = name.indexOf("/..");
+
+ // Can't be at the beginning because we have no root to refer to so
+ // we start at 1.
+ if (i > 0) {
+ int j = name.lastIndexOf("/", i - 1);
+
+ if (j >= 0) {
+ name = name.substring(0, j) + name.substring(i + 3);
+ }
+ }
+
+ return name;
+ }
+
+ public static SetLauncher configuration.
+ *
+ * @author bob mcwhirter
+ */
+public class ConfigurationException extends Exception {
+ /**
+ * Construct.
+ *
+ * @param msg The message.
+ */
+ public ConfigurationException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * Construct.
+ *
+ * @param msg The message.
+ * @param lineNo The number of configuration line where the problem occurred.
+ * @param line The configuration line where the problem occurred.
+ */
+ public ConfigurationException(String msg, int lineNo, String line) {
+ super(msg + " (" + lineNo + "): " + line);
+ }
+
+ protected ConfigurationException(Exception cause) {
+ super(cause);
+ }
+}
diff --git a/impl/maven-classworlds/src/main/java/org/codehaus/plexus/classworlds/launcher/ConfigurationHandler.java b/impl/maven-classworlds/src/main/java/org/codehaus/plexus/classworlds/launcher/ConfigurationHandler.java
new file mode 100644
index 000000000000..628055b52536
--- /dev/null
+++ b/impl/maven-classworlds/src/main/java/org/codehaus/plexus/classworlds/launcher/ConfigurationHandler.java
@@ -0,0 +1,113 @@
+/*
+ * 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.codehaus.plexus.classworlds.launcher;
+
+/*
+ * Copyright 2001-2006 Codehaus Foundation.
+ *
+ * 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.
+ */
+
+import java.io.File;
+import java.net.URL;
+
+import org.codehaus.plexus.classworlds.realm.DuplicateRealmException;
+import org.codehaus.plexus.classworlds.realm.NoSuchRealmException;
+
+/**
+ * Receive notification of the logical content of launcher configuration, independently from parsing.
+ *
+ * @author Igor Fedorenko
+ */
+public interface ConfigurationHandler {
+
+ /**
+ * Define the main class name
+ * @param mainClassName the main class name
+ * @param mainRealmName the main realm from which the main class is loaded
+ */
+ void setAppMain(String mainClassName, String mainRealmName);
+
+ /**
+ * Define a new realm
+ * @param realmName the new realm name
+ * @throws DuplicateRealmException when realm with name already exists
+ */
+ void addRealm(String realmName) throws DuplicateRealmException;
+
+ /**
+ * Add an import specification from a realm
+ * @param realmName the realm name
+ * @param importSpec the import specification
+ * @throws NoSuchRealmException if realm doesn't exist
+ */
+ void addImportFrom(String realmName, String importSpec) throws NoSuchRealmException;
+
+ /**
+ * Add a file to the realm
+ * @param file the file to load content from
+ */
+ void addLoadFile(File file);
+
+ /**
+ * Add an URL to the realm
+ * @param url the url to load content from
+ */
+ void addLoadURL(URL url);
+
+ /**
+ * Add a file to the module path. Jars added via this method will be loaded
+ * as JPMS named modules in a {@link ModuleLayer}, rather than on the classpath.
+ * @param file the jar file to add to the module path
+ */
+ default void addModuleFile(File file) {}
+
+ /**
+ * Export a package from a module to a target module.
+ * @param module the source module name
+ * @param pkg the package to export
+ * @param target the target module name, or {@code ALL-UNNAMED} for the unnamed module
+ */
+ default void addExports(String module, String pkg, String target) {}
+
+ /**
+ * Open a package from a module to a target module for deep reflection.
+ * @param module the source module name
+ * @param pkg the package to open
+ * @param target the target module name, or {@code ALL-UNNAMED} for the unnamed module
+ */
+ default void addOpens(String module, String pkg, String target) {}
+
+ /**
+ * Add a reads edge from a source module to a target module.
+ * @param source the source module name
+ * @param target the target module name
+ */
+ default void addReads(String source, String target) {}
+}
diff --git a/impl/maven-classworlds/src/main/java/org/codehaus/plexus/classworlds/launcher/ConfigurationParser.java b/impl/maven-classworlds/src/main/java/org/codehaus/plexus/classworlds/launcher/ConfigurationParser.java
new file mode 100644
index 000000000000..8a1c7a56fa2c
--- /dev/null
+++ b/impl/maven-classworlds/src/main/java/org/codehaus/plexus/classworlds/launcher/ConfigurationParser.java
@@ -0,0 +1,550 @@
+/*
+ * 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.codehaus.plexus.classworlds.launcher;
+
+/*
+ * Copyright 2001-2006 Codehaus Foundation.
+ *
+ * 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.
+ */
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.Properties;
+
+import org.codehaus.plexus.classworlds.realm.DuplicateRealmException;
+import org.codehaus.plexus.classworlds.realm.NoSuchRealmException;
+
+/**
+ * Event based launcher configuration parser, delegating effective configuration handling to ConfigurationHandler.
+ *
+ * @author bob mcwhirter
+ * @author Jason van Zyl
+ * @author Igor Fedorenko
+ * @see ConfigurationHandler
+ */
+public class ConfigurationParser {
+ public static final String MAIN_PREFIX = "main is";
+
+ public static final String SET_PREFIX = "set";
+
+ public static final String IMPORT_PREFIX = "import";
+
+ public static final String LOAD_PREFIX = "load";
+
+ public static final String MODULE_PREFIX = "module";
+
+ public static final String ADD_EXPORTS_PREFIX = "add-exports";
+
+ public static final String ADD_OPENS_PREFIX = "add-opens";
+
+ public static final String ADD_READS_PREFIX = "add-reads";
+
+ /**
+ * Optionally spec prefix.
+ */
+ public static final String OPTIONALLY_PREFIX = "optionally";
+
+ protected static final String FROM_SEPARATOR = " from ";
+
+ protected static final String USING_SEPARATOR = " using ";
+
+ protected static final String DEFAULT_SEPARATOR = " default ";
+
+ private final ConfigurationHandler handler;
+
+ private final Properties systemProperties;
+
+ public ConfigurationParser(ConfigurationHandler handler, Properties systemProperties) {
+ this.handler = handler;
+ this.systemProperties = systemProperties;
+ }
+
+ /**
+ * Parse launcher configuration file and send events to the handler.
+ *
+ * @param is the inputstream
+ * @throws IOException when IOException occurs
+ * @throws ConfigurationException when ConfigurationException occurs
+ * @throws DuplicateRealmException when realm already exists
+ * @throws NoSuchRealmException when realm doesn't exist
+ */
+ public void parse(InputStream is)
+ throws IOException, ConfigurationException, DuplicateRealmException, NoSuchRealmException {
+ try (BufferedReader reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) {
+
+ String line;
+ int lineNo = 0;
+ boolean mainSet = false;
+ String curRealm = null;
+
+ while (true) {
+ line = reader.readLine();
+
+ if (line == null) {
+ break;
+ }
+
+ ++lineNo;
+ line = line.trim();
+
+ if (canIgnore(line)) {
+ continue;
+ }
+
+ char lineFirstChar = line.charAt(0);
+ switch (lineFirstChar) {
+ case 'm':
+ if (line.startsWith(MODULE_PREFIX)) {
+ handleModuleConfiguration(line, lineNo);
+ } else {
+ mainSet = handleMainConfiguration(line, lineNo, mainSet);
+ }
+ break;
+ case 's':
+ if (handleSetConfiguration(line, lineNo)) {
+ continue;
+ }
+ break;
+ case '[':
+ curRealm = handleRealmConfiguration(line, lineNo);
+ break;
+ case 'i':
+ handleImportConfiguration(line, lineNo, curRealm);
+ break;
+ case 'l':
+ handleLoadConfiguration(line, lineNo);
+ break;
+ case 'a':
+ handleAddDirective(line, lineNo);
+ break;
+ case 'o':
+ handleOptionallyConfiguration(line, lineNo);
+ break;
+ default:
+ throw new ConfigurationException("Unhandled configuration", lineNo, line);
+ }
+ }
+ }
+ }
+
+ /**
+ * Load a glob into the specified classloader.
+ *
+ * @param line The path configuration line.
+ * @param optionally Whether the path is optional or required
+ * @throws MalformedURLException If the line does not represent
+ * a valid path element.
+ * @throws FileNotFoundException If the line does not represent
+ * a valid path element in the filesystem.
+ * @throws ConfigurationException will never occur (thrown for backwards compatibility)
+ */
+ protected void loadGlob(String line, boolean optionally)
+ throws MalformedURLException, FileNotFoundException, ConfigurationException {
+ File globFile = new File(line);
+
+ File dir = globFile.getParentFile();
+ if (!dir.exists()) {
+ if (optionally) {
+ return;
+ } else {
+ throw new FileNotFoundException(dir.toString());
+ }
+ }
+
+ String localName = globFile.getName();
+
+ int starLoc = localName.indexOf("*");
+
+ final String prefix = localName.substring(0, starLoc);
+
+ final String suffix = localName.substring(starLoc + 1);
+
+ File[] matches = dir.listFiles((dir1, name) -> {
+ if (!name.startsWith(prefix)) {
+ return false;
+ }
+
+ if (!name.endsWith(suffix)) {
+ return false;
+ }
+
+ return true;
+ });
+
+ for (File match : matches) {
+ handler.addLoadFile(match);
+ }
+ }
+
+ /**
+ * Filter a string for system properties.
+ *
+ * @param text The text to filter.
+ * @return The filtered text.
+ * @throws ConfigurationException If the property does not
+ * exist or if there is a syntax error.
+ */
+ protected String filter(String text) throws ConfigurationException {
+ StringBuilder result = new StringBuilder();
+
+ int cur = 0;
+ int textLen = text.length();
+
+ int propStart;
+ int propStop;
+
+ String propName;
+ String propValue;
+
+ while (cur < textLen) {
+ propStart = text.indexOf("${", cur);
+
+ if (propStart < 0) {
+ break;
+ }
+
+ result.append(text, cur, propStart);
+
+ propStop = text.indexOf("}", propStart);
+
+ if (propStop < 0) {
+ throw new ConfigurationException("Unterminated property: " + text.substring(propStart));
+ }
+
+ propName = text.substring(propStart + 2, propStop);
+
+ propValue = systemProperties.getProperty(propName);
+
+ /* do our best if we are not running from surefire */
+ if (propName.equals("basedir") && (propValue == null || propValue.equals(""))) {
+ propValue = (new File("")).getAbsolutePath();
+ }
+
+ if (propValue == null) {
+ throw new ConfigurationException("No such property: " + propName);
+ }
+ result.append(propValue);
+
+ cur = propStop + 1;
+ }
+
+ result.append(text.substring(cur));
+
+ return result.toString();
+ }
+
+ /**
+ * Determine if a line can be ignored because it is
+ * a comment or simply blank.
+ *
+ * @param line The line to test.
+ * @return true if the line is ignorable,
+ * otherwise false.
+ */
+ private boolean canIgnore(String line) {
+ return (line.isEmpty() || line.startsWith("#"));
+ }
+
+ private boolean handleMainConfiguration(String line, int lineNo, boolean mainSet) throws ConfigurationException {
+ if (line.startsWith(MAIN_PREFIX)) {
+ if (mainSet) {
+ throw new ConfigurationException("Duplicate main configuration", lineNo, line);
+ }
+
+ int fromLoc = line.indexOf(FROM_SEPARATOR, MAIN_PREFIX.length());
+
+ if (fromLoc < 0) {
+ throw new ConfigurationException("Missing from clause", lineNo, line);
+ }
+
+ String mainClassName =
+ filter(line.substring(MAIN_PREFIX.length(), fromLoc).trim());
+
+ String mainRealmName =
+ filter(line.substring(fromLoc + FROM_SEPARATOR.length()).trim());
+
+ this.handler.setAppMain(mainClassName, mainRealmName);
+
+ return true;
+ }
+ throw new ConfigurationException("Unhandled configuration", lineNo, line);
+ }
+
+ private boolean handleSetConfiguration(String line, int lineNo) throws ConfigurationException {
+ if (line.startsWith(SET_PREFIX)) {
+ String conf = line.substring(SET_PREFIX.length()).trim();
+
+ int usingLoc = conf.indexOf(USING_SEPARATOR);
+
+ String property = null;
+ String propertiesFileName = null;
+
+ if (usingLoc >= 0) {
+ property = conf.substring(0, usingLoc).trim();
+ propertiesFileName = filter(
+ conf.substring(usingLoc + USING_SEPARATOR.length()).trim());
+ conf = propertiesFileName;
+ }
+
+ String defaultValue = null;
+ int defaultLoc = conf.indexOf(DEFAULT_SEPARATOR);
+
+ if (defaultLoc >= 0) {
+ defaultValue = filter(
+ conf.substring(defaultLoc + DEFAULT_SEPARATOR.length()).trim());
+
+ if (property == null) {
+ property = conf.substring(0, defaultLoc).trim();
+ } else {
+ propertiesFileName = conf.substring(0, defaultLoc).trim();
+ }
+ }
+
+ String value = systemProperties.getProperty(property);
+
+ if (value != null) {
+ return true;
+ }
+
+ if (propertiesFileName != null) {
+ File propertiesFile = new File(propertiesFileName);
+
+ if (propertiesFile.exists()) {
+ Properties properties = new Properties();
+
+ try (InputStream inputStream = Files.newInputStream(Paths.get(propertiesFileName))) {
+ properties.load(inputStream);
+ value = properties.getProperty(property);
+ } catch (Exception e) {
+ // do nothing
+ }
+ }
+ }
+
+ if (value == null && defaultValue != null) {
+ value = defaultValue;
+ }
+
+ if (value != null) {
+ value = filter(value);
+ systemProperties.setProperty(property, value);
+ }
+
+ return false;
+ }
+ throw new ConfigurationException("Unhandled configuration", lineNo, line);
+ }
+
+ private String handleRealmConfiguration(String line, int lineNo)
+ throws ConfigurationException, DuplicateRealmException {
+ int rbrack = line.indexOf("]");
+
+ if (rbrack < 0) {
+ throw new ConfigurationException("Invalid realm specifier", lineNo, line);
+ }
+
+ String realmName = line.substring(1, rbrack);
+ handler.addRealm(realmName);
+ return realmName;
+ }
+
+ private void handleImportConfiguration(String line, int lineNo, String curRealm)
+ throws ConfigurationException, NoSuchRealmException {
+ if (line.startsWith(IMPORT_PREFIX)) {
+ if (curRealm == null) {
+ throw new ConfigurationException("Unhandled import", lineNo, line);
+ }
+ int fromLoc = line.indexOf(FROM_SEPARATOR, IMPORT_PREFIX.length());
+
+ if (fromLoc < 0) {
+ throw new ConfigurationException("Missing from clause", lineNo, line);
+ }
+
+ String importSpec = line.substring(IMPORT_PREFIX.length(), fromLoc).trim();
+ String realmName = line.substring(fromLoc + FROM_SEPARATOR.length()).trim();
+
+ handler.addImportFrom(realmName, importSpec);
+ return;
+ }
+ throw new ConfigurationException("Unhandled configuration", lineNo, line);
+ }
+
+ private void handleLoadConfiguration(String line, int lineNo)
+ throws ConfigurationException, FileNotFoundException, MalformedURLException {
+ if (line.startsWith(LOAD_PREFIX)) {
+ String constituent = line.substring(LOAD_PREFIX.length()).trim();
+ constituent = filter(constituent);
+
+ if (constituent.contains("*")) {
+ loadGlob(constituent, false /*not optionally*/);
+ } else {
+ File file = new File(constituent);
+
+ if (file.exists()) {
+ handler.addLoadFile(file);
+ } else {
+ try {
+ handler.addLoadURL(new URL(constituent));
+ } catch (MalformedURLException e) {
+ throw new FileNotFoundException(constituent);
+ }
+ }
+ }
+ return;
+ }
+ throw new ConfigurationException("Unhandled configuration", lineNo, line);
+ }
+
+ private void handleModuleConfiguration(String line, int lineNo)
+ throws ConfigurationException, FileNotFoundException, MalformedURLException {
+ if (line.startsWith(MODULE_PREFIX)) {
+ String constituent = line.substring(MODULE_PREFIX.length()).trim();
+ constituent = filter(constituent);
+
+ if (constituent.contains("*")) {
+ moduleGlob(constituent);
+ } else {
+ File file = new File(constituent);
+
+ if (file.exists()) {
+ handler.addModuleFile(file);
+ } else {
+ throw new FileNotFoundException(constituent);
+ }
+ }
+ return;
+ }
+ throw new ConfigurationException("Unhandled configuration", lineNo, line);
+ }
+
+ private void handleAddDirective(String line, int lineNo) throws ConfigurationException {
+ if (line.startsWith(ADD_EXPORTS_PREFIX)) {
+ String spec = line.substring(ADD_EXPORTS_PREFIX.length()).trim();
+ parseModulePackageDirective(spec, lineNo, line, handler::addExports);
+ } else if (line.startsWith(ADD_OPENS_PREFIX)) {
+ String spec = line.substring(ADD_OPENS_PREFIX.length()).trim();
+ parseModulePackageDirective(spec, lineNo, line, handler::addOpens);
+ } else if (line.startsWith(ADD_READS_PREFIX)) {
+ String spec = line.substring(ADD_READS_PREFIX.length()).trim();
+ int eqLoc = spec.indexOf('=');
+ if (eqLoc < 0) {
+ throw new ConfigurationException("Missing '=' in add-reads directive", lineNo, line);
+ }
+ String source = spec.substring(0, eqLoc).trim();
+ String target = spec.substring(eqLoc + 1).trim();
+ handler.addReads(source, target);
+ } else {
+ throw new ConfigurationException("Unhandled configuration", lineNo, line);
+ }
+ }
+
+ private void parseModulePackageDirective(String spec, int lineNo, String line, ModulePackageHandler mph)
+ throws ConfigurationException {
+ int slashLoc = spec.indexOf('/');
+ if (slashLoc < 0) {
+ throw new ConfigurationException("Missing '/' in module/package directive", lineNo, line);
+ }
+ String module = spec.substring(0, slashLoc).trim();
+ String rest = spec.substring(slashLoc + 1).trim();
+ String pkg;
+ String target;
+ int eqLoc = rest.indexOf('=');
+ if (eqLoc >= 0) {
+ pkg = rest.substring(0, eqLoc).trim();
+ target = rest.substring(eqLoc + 1).trim();
+ } else {
+ pkg = rest;
+ target = "ALL-UNNAMED";
+ }
+ mph.handle(module, pkg, target);
+ }
+
+ @FunctionalInterface
+ private interface ModulePackageHandler {
+ void handle(String module, String pkg, String target);
+ }
+
+ protected void moduleGlob(String line) throws MalformedURLException, FileNotFoundException {
+ File globFile = new File(line);
+
+ File dir = globFile.getParentFile();
+ if (!dir.exists()) {
+ return;
+ }
+
+ String localName = globFile.getName();
+ int starLoc = localName.indexOf("*");
+ final String prefix = localName.substring(0, starLoc);
+ final String suffix = localName.substring(starLoc + 1);
+
+ File[] matches = dir.listFiles((dir1, name) -> name.startsWith(prefix) && name.endsWith(suffix));
+
+ if (matches != null) {
+ for (File match : matches) {
+ handler.addModuleFile(match);
+ }
+ }
+ }
+
+ private void handleOptionallyConfiguration(String line, int lineNo)
+ throws ConfigurationException, FileNotFoundException, MalformedURLException {
+ if (line.startsWith(OPTIONALLY_PREFIX)) {
+ String constituent = line.substring(OPTIONALLY_PREFIX.length()).trim();
+ constituent = filter(constituent);
+
+ if (constituent.contains("*")) {
+ loadGlob(constituent, true /*optionally*/);
+ } else {
+ File file = new File(constituent);
+
+ if (file.exists()) {
+ handler.addLoadFile(file);
+ } else {
+ try {
+ handler.addLoadURL(new URL(constituent));
+ } catch (MalformedURLException e) {
+ // swallow
+ }
+ }
+ }
+ return;
+ }
+ throw new ConfigurationException("Unhandled configuration", lineNo, line);
+ }
+}
diff --git a/impl/maven-classworlds/src/main/java/org/codehaus/plexus/classworlds/launcher/Configurator.java b/impl/maven-classworlds/src/main/java/org/codehaus/plexus/classworlds/launcher/Configurator.java
new file mode 100644
index 000000000000..0d8107b59347
--- /dev/null
+++ b/impl/maven-classworlds/src/main/java/org/codehaus/plexus/classworlds/launcher/Configurator.java
@@ -0,0 +1,339 @@
+/*
+ * 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.codehaus.plexus.classworlds.launcher;
+
+/*
+ * Copyright 2001-2006 Codehaus Foundation.
+ *
+ * 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.
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.module.Configuration;
+import java.lang.module.ModuleFinder;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.codehaus.plexus.classworlds.ClassWorld;
+import org.codehaus.plexus.classworlds.realm.ClassRealm;
+import org.codehaus.plexus.classworlds.realm.DuplicateRealmException;
+import org.codehaus.plexus.classworlds.realm.NoSuchRealmException;
+
+/**
+ * Launcher configurator.
+ *
+ * @author bob mcwhirter
+ * @author Jason van Zyl
+ */
+public class Configurator implements ConfigurationHandler {
+ /**
+ * The launcher to configure.
+ */
+ private Launcher launcher;
+
+ private ClassWorld world;
+
+ /**
+ * Processed Realms.
+ */
+ private MapCommand-line invokable application launcher.
+ * + *This launcher class assists in the creation of classloaders and ClassRealms
+ * from a configuration file and the launching of the application's main
+ * method from the correct class loaded through the correct classloader.
The path to the configuration file is specified using the classworlds.conf
+ * system property, typically specified using the -D switch to
+ * java.
Attempt to launch the application through the enhanced main method.
+ * + *This will seek a method with the exact signature of:
+ *+ * public static void main(String[] args, ClassWorld world) + *+ * + * @param args The application args. + * @throws ClassNotFoundException If the main entry class cannot be found. + * @throws IllegalAccessException If the method cannot be accessed. + * @throws InvocationTargetException If the target of the invokation is + * invalid. + * @throws NoSuchMethodException If the main entry method cannot be found. + * @throws NoSuchRealmException If the main entry realm cannot be found. + */ + protected void launchEnhanced(String[] args) + throws ClassNotFoundException, IllegalAccessException, InvocationTargetException, NoSuchMethodException, + NoSuchRealmException { + ClassRealm mainRealm = getMainRealm(); + + Class> mainClass = getMainClass(); + + Method mainMethod = getEnhancedMainMethod(); + + ClassLoader cl = mainRealm; + + // ---------------------------------------------------------------------- + // This is what the classloader for the main realm looks like when we + // boot from the command line: + // ---------------------------------------------------------------------- + // [ AppLauncher$AppClassLoader ] : $CLASSPATH envar + // ^ + // | + // | + // [ AppLauncher$ExtClassLoader ] : ${java.home}/jre/lib/ext/*.jar + // ^ + // | + // | + // [ Strategy ] + // ---------------------------------------------------------------------- + + Thread.currentThread().setContextClassLoader(cl); + + Object ret = mainMethod.invoke(mainClass, args, getWorld()); + + if (ret instanceof Integer) { + exitCode = (Integer) ret; + } + + Thread.currentThread().setContextClassLoader(systemClassLoader); + } + + /** + *
Attempt to launch the application through the standard main method.
+ * + *This will seek a method with the exact signature of:
+ * + *+ * public static void main(String[] args) + *+ * + * @param args The application args. + * @throws ClassNotFoundException If the main entry class cannot be found. + * @throws IllegalAccessException If the method cannot be accessed. + * @throws InvocationTargetException If the target of the invokation is + * invalid. + * @throws NoSuchMethodException If the main entry method cannot be found. + * @throws NoSuchRealmException If the main entry realm cannot be found. + */ + protected void launchStandard(String[] args) + throws ClassNotFoundException, IllegalAccessException, InvocationTargetException, NoSuchMethodException, + NoSuchRealmException { + ClassRealm mainRealm = getMainRealm(); + + Class> mainClass = getMainClass(); + + Method mainMethod = getMainMethod(); + + Thread.currentThread().setContextClassLoader(mainRealm); + + Object ret = mainMethod.invoke(mainClass, new Object[] {args}); + + if (ret instanceof Integer) { + exitCode = (Integer) ret; + } + + Thread.currentThread().setContextClassLoader(systemClassLoader); + } + + // ------------------------------------------------------------ + // Class methods + // ------------------------------------------------------------ + + /** + * Launch the launcher from the command line. + * Will exit using System.exit with an exit code of 0 for success, 100 if there was an unknown exception, + * or some other code for an application error. + * + * @param args The application command-line arguments. + */ + public static void main(String[] args) { + try { + int exitCode = mainWithExitCode(args); + + System.exit(exitCode); + } catch (Exception e) { + e.printStackTrace(); + + System.exit(100); + } + } + + /** + * Launch the launcher. + * + * @param args The application command-line arguments. + * @return an integer exit code + * @throws Exception If an error occurs. + */ + public static int mainWithExitCode(String[] args) throws Exception { + String classworldsConf = System.getProperty(CLASSWORLDS_CONF); + + InputStream is; + + Launcher launcher = new Launcher(); + + ClassLoader cl = Thread.currentThread().getContextClassLoader(); + + launcher.setSystemClassLoader(cl); + + if (classworldsConf != null) { + is = Files.newInputStream(Paths.get(classworldsConf)); + } else { + if ("true".equals(System.getProperty("classworlds.bootstrapped"))) { + is = cl.getResourceAsStream(UBERJAR_CONF_DIR + CLASSWORLDS_CONF); + } else { + is = cl.getResourceAsStream(CLASSWORLDS_CONF); + } + } + + if (is == null) { + throw new Exception("classworlds configuration not specified nor found in the classpath"); + } + + launcher.configure(is); + + is.close(); + + try { + launcher.launch(args); + } catch (InvocationTargetException e) { + ClassRealm realm = launcher.getWorld().getRealm(launcher.getMainRealmName()); + + URL[] constituents = realm.getURLs(); + + System.out.println("---------------------------------------------------"); + + for (int i = 0; i < constituents.length; i++) { + System.out.println("constituent[" + i + "]: " + constituents[i]); + } + + System.out.println("---------------------------------------------------"); + + // Decode ITE (if we can) + Throwable t = e.getTargetException(); + + if (t instanceof Exception) { + throw (Exception) t; + } + if (t instanceof Error) { + throw (Error) t; + } + + // Else just toss the ITE + throw e; + } + + return launcher.getExitCode(); + } +} diff --git a/impl/maven-classworlds/src/main/java/org/codehaus/plexus/classworlds/realm/ClassRealm.java b/impl/maven-classworlds/src/main/java/org/codehaus/plexus/classworlds/realm/ClassRealm.java new file mode 100644 index 000000000000..96ffa7593387 --- /dev/null +++ b/impl/maven-classworlds/src/main/java/org/codehaus/plexus/classworlds/realm/ClassRealm.java @@ -0,0 +1,556 @@ +/* + * 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.codehaus.plexus.classworlds.realm; + +/* + * Copyright 2001-2006 Codehaus Foundation. + * + * 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. + */ + +import java.io.Closeable; +import java.io.IOException; +import java.io.PrintStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.Collection; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.SortedSet; +import java.util.TreeSet; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import org.codehaus.plexus.classworlds.ClassWorld; +import org.codehaus.plexus.classworlds.strategy.Strategy; +import org.codehaus.plexus.classworlds.strategy.StrategyFactory; + +/** + * The class loading gateway. Each class realm has access to a base class loader, imports form zero or more other class + * loaders, an optional parent class loader and of course its own class path. When queried for a class/resource, a class + * realm will always query its base class loader first before it delegates to a pluggable strategy. The strategy in turn + * controls the order in which imported class loaders, the parent class loader and the realm itself are searched. The + * base class loader is assumed to be capable of loading of the bootstrap classes. + * + * @author bob mcwhirter + * @author Jason van Zyl + */ +public class ClassRealm extends URLClassLoader implements org.apache.maven.api.classworlds.ClassRealm { + + private ClassWorld world; + + private String id; + + private SortedSet
null.
+ * @param id The identifier for this realm, must not be null.
+ * @param baseClassLoader The base class loader for this realm, may be null to use the bootstrap class
+ * loader.
+ */
+ public ClassRealm(ClassWorld world, String id, ClassLoader baseClassLoader) {
+ super(new URL[0], baseClassLoader);
+
+ this.world = world;
+
+ this.id = id;
+
+ foreignImports = new TreeSet<>();
+
+ strategy = StrategyFactory.getStrategy(this);
+
+ lockMap = IS_PARALLEL_CAPABLE ? new ConcurrentHashMap<>() : null;
+
+ if (IS_PARALLEL_CAPABLE) {
+ // We must call super.getClassLoadingLock at least once
+ // to avoid NPE in super.loadClass.
+ super.getClassLoadingLock(getClass().getName());
+ }
+ }
+
+ public String getId() {
+ return this.id;
+ }
+
+ public ClassWorld getWorld() {
+ return this.world;
+ }
+
+ /**
+ * Returns the underlying ClassLoader for this realm.
+ * + * This method allows access to the actual ClassLoader implementation + * while maintaining API abstraction. Since ClassRealm extends URLClassLoader, + * this method returns {@code this}. + *
+ * + * @return the underlying ClassLoader (this instance) + */ + public ClassLoader getClassLoader() { + return this; + } + + public void importFromParent(String packageName) { + if (parentImports == null) { + parentImports = new TreeSet<>(); + } + + parentImports.add(new Entry(null, packageName)); + } + + boolean isImportedFromParent(String name) { + if (parentImports != null && !parentImports.isEmpty()) { + for (Entry entry : parentImports) { + if (entry.matches(name)) { + return true; + } + } + + return false; + } + + return true; + } + + public void importFrom(String realmId, String packageName) throws NoSuchRealmException { + importFrom(getWorld().getRealm(realmId), packageName); + } + + public void importFrom(ClassLoader classLoader, String packageName) { + foreignImports.add(new Entry(classLoader, packageName)); + } + + public ClassLoader getImportClassLoader(String name) { + for (Entry entry : foreignImports) { + if (entry.matches(name)) { + return entry.getClassLoader(); + } + } + + return null; + } + + public CollectionClassRealm to a
+ * ClassWorld with a duplicate id.
+ *
+ * @author bob mcwhirter
+ */
+public class DuplicateRealmException extends org.apache.maven.api.classworlds.DuplicateRealmException {
+ // ------------------------------------------------------------
+ // Instance members
+ // ------------------------------------------------------------
+
+ /**
+ * The realm id.
+ */
+ private String id;
+
+ // ------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------
+
+ /**
+ * Construct.
+ *
+ * @param world The world.
+ * @param id The realm id.
+ */
+ public DuplicateRealmException(ClassWorld world, String id) {
+ super(world, id);
+ this.id = id;
+ }
+
+ // ------------------------------------------------------------
+ // Instance methods
+ // ------------------------------------------------------------
+
+ /**
+ * Retrieve the duplicate realm id.
+ *
+ * @return The id.
+ */
+ public String getId() {
+ return this.id;
+ }
+
+ /**
+ * Retrieve the world.
+ *
+ * @return The world.
+ */
+ public ClassWorld getWorld() {
+ return (ClassWorld) super.getWorld();
+ }
+}
diff --git a/impl/maven-classworlds/src/main/java/org/codehaus/plexus/classworlds/realm/Entry.java b/impl/maven-classworlds/src/main/java/org/codehaus/plexus/classworlds/realm/Entry.java
new file mode 100644
index 000000000000..316c3c7ff4cf
--- /dev/null
+++ b/impl/maven-classworlds/src/main/java/org/codehaus/plexus/classworlds/realm/Entry.java
@@ -0,0 +1,212 @@
+/*
+ * 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.codehaus.plexus.classworlds.realm;
+
+/*
+ * Copyright 2001-2006 Codehaus Foundation.
+ *
+ * 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.
+ */
+
+/**
+ * Import description entry.
+ *
+ * @author bob mcwhirter
+ */
+class Entry implements Comparablenull.
+ * @return true if this entry matches the
+ * classname, otherwise false.
+ */
+ boolean matches(String name) {
+ String pkg = getPackageName();
+
+ if (pkg.endsWith(".*")) {
+ String pkgName;
+
+ if (name.indexOf('/') < 0) {
+ // a binary class name, e.g. java.lang.Object
+
+ int index = name.lastIndexOf('.');
+ pkgName = (index < 0) ? "" : name.substring(0, index);
+ } else {
+ // a resource name, e.g. java/lang/Object.class
+
+ int index = name.lastIndexOf('/');
+ pkgName = (index < 0) ? "" : name.substring(0, index).replace('/', '.');
+ }
+
+ return pkgName.length() == pkg.length() - 2 && pkg.regionMatches(0, pkgName, 0, pkgName.length());
+ } else if (pkg.length() > 0) {
+ if (name.indexOf('/') < 0) {
+ // a binary class name, e.g. java.lang.Object
+
+ if (name.startsWith(pkg)) {
+ if (name.length() == pkg.length()) {
+ // exact match of class name
+ return true;
+ } else if (name.charAt(pkg.length()) == '.') {
+ // prefix match of package name
+ return true;
+ } else if (name.charAt(pkg.length()) == '$') {
+ // prefix match of enclosing type
+ return true;
+ }
+ }
+ } else {
+ // a resource name, e.g. java/lang/Object.class
+
+ if (name.equals(pkg)) {
+ // exact match of resource name
+ return true;
+ }
+
+ pkg = pkg.replace('.', '/');
+
+ if (name.startsWith(pkg) && name.length() > pkg.length()) {
+ if (name.charAt(pkg.length()) == '/') {
+ // prefix match of package directory
+ return true;
+ } else if (name.charAt(pkg.length()) == '$') {
+ // prefix match of nested class file
+ return true;
+ } else if (name.length() == pkg.length() + 6 && name.endsWith(".class")) {
+ // exact match of class file
+ return true;
+ }
+ }
+ }
+
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ // java.lang.Comparable
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+ /**
+ * Compare this entry to another for relative ordering.
+ *
+ *
+ * The natural ordering of Entry objects is reverse-alphabetical
+ * based upon package name.
+ *
+ *
+ * @param that The object to compare.
+ * @return -1 if this object sorts before that object, 0
+ * if they are equal, or 1 if this object sorts
+ * after that object.
+ */
+ public int compareTo(Entry that) {
+ // We are reverse sorting this list, so that
+ // we get longer matches first:
+ //
+ // com.werken.foo.bar
+ // com.werken.foo
+ // com.werken
+
+ return -(getPackageName().compareTo(that.getPackageName()));
+ }
+
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ // java.lang.Object
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+ /**
+ * Test this entry for equality to another.
+ *
+ *
+ * Consistent with {@link #compareTo}, this method tests
+ * for equality purely on the package name.
+ *
+ *
+ * @param thatObj The object to compare
+ * @return true if the two objects are
+ * semantically equivalent, otherwise false.
+ */
+ public boolean equals(Object thatObj) {
+ Entry that = (Entry) thatObj;
+
+ return getPackageName().equals(that.getPackageName());
+ }
+
+ /**
+ *
+ * Consistent with {@link #equals}, this method creates a hashCode
+ * based on the packagename.
+ *
+ */
+ public int hashCode() {
+ return getPackageName().hashCode();
+ }
+
+ public String toString() {
+ return "Entry[import " + getPackageName() + " from realm " + getClassLoader() + "]";
+ }
+}
diff --git a/impl/maven-classworlds/src/main/java/org/codehaus/plexus/classworlds/realm/FilteredClassRealm.java b/impl/maven-classworlds/src/main/java/org/codehaus/plexus/classworlds/realm/FilteredClassRealm.java
new file mode 100644
index 000000000000..dfb2eefa9166
--- /dev/null
+++ b/impl/maven-classworlds/src/main/java/org/codehaus/plexus/classworlds/realm/FilteredClassRealm.java
@@ -0,0 +1,74 @@
+/*
+ * 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.codehaus.plexus.classworlds.realm;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.function.Predicate;
+
+import org.codehaus.plexus.classworlds.ClassWorld;
+
+/**
+ * Similar to {@link ClassRealm} but only exposing some resources of the underlying URL.
+ * Only supposed to be called from {@link ClassWorld}.
+ */
+public class FilteredClassRealm extends ClassRealm {
+ private final Predicatenull.
+ * @param id The identifier for this realm, must not be null.
+ * @param baseClassLoader The base class loader for this realm, may be null to use the bootstrap class
+ * loader.
+ */
+ public FilteredClassRealm(PredicateClassRealm from a
+ * ClassWorld with an invalid id.
+ *
+ * @author bob mcwhirter
+ */
+public class NoSuchRealmException extends org.apache.maven.api.classworlds.NoSuchRealmException {
+ // ------------------------------------------------------------
+ // Instance members
+ // ------------------------------------------------------------
+
+ /**
+ * The realm id.
+ */
+ private String id;
+
+ // ------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------
+
+ /**
+ * Construct.
+ *
+ * @param world The world.
+ * @param id The realm id.
+ */
+ public NoSuchRealmException(ClassWorld world, String id) {
+ super(world, id);
+ this.id = id;
+ }
+
+ // ------------------------------------------------------------
+ // Instance methods
+ // ------------------------------------------------------------
+
+ /**
+ * Retrieve the invalid realm id.
+ *
+ * @return The id.
+ */
+ public String getId() {
+ return this.id;
+ }
+
+ /**
+ * Retrieve the world.
+ *
+ * @return The world.
+ */
+ public ClassWorld getWorld() {
+ return (ClassWorld) super.getWorld();
+ }
+}
diff --git a/impl/maven-classworlds/src/main/java/org/codehaus/plexus/classworlds/strategy/AbstractStrategy.java b/impl/maven-classworlds/src/main/java/org/codehaus/plexus/classworlds/strategy/AbstractStrategy.java
new file mode 100644
index 000000000000..91af5b3cfdd9
--- /dev/null
+++ b/impl/maven-classworlds/src/main/java/org/codehaus/plexus/classworlds/strategy/AbstractStrategy.java
@@ -0,0 +1,82 @@
+/*
+ * 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.codehaus.plexus.classworlds.strategy;
+
+import java.net.URL;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.LinkedHashSet;
+
+import org.codehaus.plexus.classworlds.UrlUtils;
+import org.codehaus.plexus.classworlds.realm.ClassRealm;
+
+/*
+ * Copyright 2001-2006 Codehaus Foundation.
+ *
+ * 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.
+ */
+
+/**
+ * @author Jason van Zyl
+ */
+public abstract class AbstractStrategy implements Strategy {
+
+ protected ClassRealm realm;
+
+ public AbstractStrategy(ClassRealm realm) {
+ this.realm = realm;
+ }
+
+ protected String getNormalizedResource(String name) {
+ return UrlUtils.normalizeUrlPath(name);
+ }
+
+ protected Enumeration+ * All plugin artifacts are placed on the module path and resolved via + * {@link java.lang.module.Configuration#resolveAndBind}. There is no fallback to classpath loading — + * if the module graph cannot be resolved (e.g. split packages), this method throws. + *
+ * + * @param plugin The plugin for which to create a modular realm, must not be {@code null}. + * @param parent The parent class loader, may be {@code null}. + * @param artifacts The artifacts to place on the module path, may be {@code null}. + * @return The new modular plugin realm with an associated {@link ModuleLayer}. + * @throws ModuleLayerCreationException if the module layer cannot be created. + * @since 4.1.0 + */ + ClassRealm createModularPluginRealm(Plugin plugin, ClassLoader parent, List+ * When a plugin (or extension) runs on the classpath (unnamed module) it may need to + * call into packages of a named module that lives in Maven's boot/runtime layer — + * for example JLine modules in {@code lib/modules/}, or any future Maven API module that ships + * as a named module. Named modules do not export their internals to the unnamed module by + * default; the JVM enforces this at runtime via strong encapsulation. + *
+ *+ * The {@code META-INF/maven/module-access} file is a plugin-side escape hatch: it lets the + * plugin declare which packages of which boot-layer modules it needs opened or exported + * to itself (always {@code ALL-UNNAMED} as the target). Maven applies these + * directives programmatically via {@link Module#addExports}/{@link Module#addOpens} on startup + * of the plugin realm, before any plugin class is loaded. + *
+ * + *+ * Directives go from an existing named module in the boot/runtime layer + * to the unnamed-module classloader of the plugin. In other words: + * a plugin cannot use this mechanism to export its own packages; it can only + * widen access from modules that Maven already owns (and that are loaded before the plugin). + *
+ * + *Each non-blank, non-comment line is one of:
+ *+ * add-exports <module>/<package>=ALL-UNNAMED + * add-opens <module>/<package>=ALL-UNNAMED + * add-reads <module> + *+ *
+ * These mirror the JVM flags {@code --add-exports}, {@code --add-opens}, and + * {@code --add-reads} respectively. Lines starting with {@code #} are comments. + *
+ * + *+ * The boot-layer modules (e.g. JLine) are compiled independently and cannot reference + * the plugin's module name at compile time. Adding {@code exports … to plugin.module} in + * their {@code module-info} would create an unacceptable coupling. Programmatic + * {@code addExports}/{@code addOpens} is the standard JDK-endorsed workaround for + * this exact scenario (see {@link java.lang.Module#addExports}). + *
+ * + * @param classRealm the plugin class realm whose JAR(s) are scanned for descriptors + */ + private void applyModuleAccessDescriptors(ClassRealm classRealm) { + var implRealm = (org.codehaus.plexus.classworlds.realm.ClassRealm) classRealm; + try { + Enumeration
+ * This is a hard error with no fallback: if a plugin declares {@code
+ * The default implementation delegates to
+ * {@link #createKey(Plugin, ClassLoader, Map, DependencyFilter, List, RepositorySystemSession)}
+ * and ignores the {@code modular} flag; override in implementations that support modular plugins.
+ *
+ * @param modular {@code true} if the plugin is loaded as a JPMS module layer
+ */
+ default Key createKey(
+ Plugin plugin,
+ ClassLoader parentRealm,
+ Map