Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/Java/Netbeans/platform/o.n.bootstrap/src/org/netbeans/   (Apache JAVA IDE Version 28©)  Datei vom 3.10.2025 mit Größe 24 kB image not shown  

Quelle  Module.java   Sprache: JAVA

 
/*
 * 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.netbeans;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.lang.reflect.Method;
import java.net.URL;
import java.security.CodeSource;
import java.util.*;
import java.util.jar.Manifest;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.openide.modules.Dependency;
import org.openide.modules.ModuleInfo;
import org.openide.modules.SpecificationVersion;
import org.openide.util.Enumerations;
import org.openide.util.Exceptions;
import org.openide.util.Union2;

/** Object representing one module, possibly installed.
 * Responsible for opening of module JAR file; reading
 * manifest; parsing basic information such as dependencies;
 * and creating a classloader for use by the installer.
 * Methods not defined in ModuleInfo must be called from within
 * the module manager's read mutex as a rule.
 * @author Jesse Glick
 * @since 2.1 the class was made public abstract
 */

public abstract class Module extends ModuleInfo {
    
    public static final String PROP_RELOADABLE = "reloadable"// NOI18N
    public static final String PROP_CLASS_LOADER = "classLoader"// NOI18N
    public static final String PROP_MANIFEST = "manifest"// NOI18N
    public static final String PROP_VALID = "valid"// NOI18N
    public static final String PROP_PROBLEMS = "problems"// NOI18N

    /** manager which owns this module */
    protected final ModuleManager mgr;
    /** event logging (should not be much here) */
    protected final Events events;
    /** associated history object
     * @see <a href="@org-netbeans-core-startup@/org/netbeans/core/startup/ModuleHistory.html">ModuleHistory</a>
     */

    private final Object history;
    /** true if currently enabled; manipulated by ModuleManager */
    private boolean enabled;
    /** whether it is supposed to be automatically loaded when required */
    private final boolean autoload;
    /** */
    protected boolean reloadable;
    /** if true, this module is eagerly turned on whenever it can be */
    private final boolean eager;
    /** currently active module classloader */
    protected ClassLoader classloader;

    private ModuleData data;
    private NbInstrumentation instr;
    
    private static final Object DATA_LOCK = new Object();

    /** Use ModuleManager.create as a factory. */
    protected Module(ModuleManager mgr, Events ev, Object history, boolean reloadable, boolean autoload, boolean eager) throws IOException {
        if (autoload && eager) throw new IllegalArgumentException("A module may not be both autoload and eager"); // NOI18N
        this.mgr = mgr;
        this.events = ev;
        this.history = history;
        this.reloadable = reloadable;
        this.autoload = autoload;
        this.eager = eager;
        this.enabled = false;
    }
    
    /** Create a special-purpose "fixed" JAR. */
    protected Module(ModuleManager mgr, Events ev, Object history, ClassLoader classloader) throws InvalidException {
        this(mgr, ev, history, classloader, falsefalse);
    }
    
    /**
     * Create a special-purpose "fixed" JAR which may nonetheless be marked eager or autoload.
     * @since 2.7
     */

    protected Module(ModuleManager mgr, Events ev, Object history, ClassLoader classloader, boolean autoload, boolean eager) throws InvalidException {
        if (autoload && eager) throw new IllegalArgumentException("A module may not be both autoload and eager"); // NOI18N
        this.mgr = mgr;
        this.events = ev;
        this.history = history;
        this.classloader = classloader;
        reloadable = false;
        this.autoload = autoload;
        this.eager = eager;
        enabled = false;
    }
    
    ModuleData createData(ObjectInput in, Manifest mf) throws IOException {
        if (in != null) {
            return new ModuleData(in);
        } else {
            return new ModuleData(mf, this);
        }
    }
    
    final void writeData(ObjectOutput out) throws IOException {
        data().write(out);
    }
    
    final ModuleData data() {
        try {
            return dataWithCheck();
        } catch (InvalidException ex) {
            throw new IllegalStateException(ex);
        }
    }
    
    final ModuleData dataWithCheck() throws InvalidException {
        synchronized (DATA_LOCK) {
            if (data != null) {
                return data;
            }
            Util.err.log(Level.FINE, "Initialize data {0}", getJarFile()); // NOI18N
            InputStream is = mgr.dataFor(getJarFile());
            if (is != null) {
                try {
                    ObjectInputStream ois = new ObjectInputStream(is);
                    ModuleData mine = createData(ois, null);
                    ois.close();
                    assert data == null;
                    data = mine;
                    return mine;
                } catch (IOException ex) {
                    Util.err.log(Level.INFO, "Cannot read cache for " + getJarFile(), ex); // NOI18N
                }
            }
            try {
                ModuleData mine = createData(null, getManifest());
                assert mine == data;
                return mine;
            } catch (InvalidException ex) {
                throw ex;
            } catch (IOException ex) {
                // no I/O needed when reading from manifest
                throw new IllegalStateException(ex);
            }
        }
    }
    
    final void assignData(ModuleData data) {
        assert Thread.holdsLock(DATA_LOCK);
        this.data = data;
    }
    
    /** Get the associated module manager. */
    public ModuleManager getManager() {
        return mgr;
    }
    
    @Override
    public boolean isEnabled() {
        return enabled;
    }
    
    // Access from ModuleManager:
    void setEnabled(boolean enabled) {
        /* #13647: actually can happen if loading of bootstrap modules is rolled back: */
        if (isFixed() && ! enabled) throw new IllegalStateException("Cannot disable a fixed module: " + this); // NOI18N
        this.enabled = enabled;
    }
    
    /** Normally a module once created and managed is valid
     * (that is, either installed or not, but at least managed).
     * If it is deleted any remaining references to it become
     * invalid.
     */

    public boolean isValid() {
        return mgr.get(getCodeNameBase()) == this;
    }
    
    /** Is this module automatically loaded?
     * If so, no information about its state is kept
     * permanently beyond the existence of its JAR file;
     * it is enabled when some real module needs it to be,
     * and disabled when this is no longer the case.
     * @see <a href="https://bz.apache.org/netbeans/show_bug.cgi?id=9779">#9779</a>
     */

    public boolean isAutoload() {
        return autoload;
    }
    
    /** Is this module eagerly enabled?
     * If so, no information about its state is kept permanently.
     * It is turned on whenever it can be, i.e. whenever it meets all of
     * its dependencies. This may be used to implement "bridge" modules with
     * simple functionality that just depend on two normal modules.
     * A module may not be simultaneously eager and autoload.
     * @see <a href="https://bz.apache.org/netbeans/show_bug.cgi?id=17501">#17501</a>
     * @since org.netbeans.core/1 1.3
     */

    public boolean isEager() {
        return eager;
    }
    
    /** Get an associated arbitrary attribute.
     * Right now, simply provides the main attributes of the manifest.
     * In the future some of these could be suppressed (if only of dangerous
     * interest, e.g. Class-Path) or enhanced with other information available
     * from the core (if needed).
     */

    @Override
    public Object getAttribute(String attr) {
        return getManifest().getMainAttributes().getValue(attr);
    }
    
    @Override
    public String getCodeName() {
        return data().getCodeName();
    }
    
    String getFragmentHostCodeName() {
        String fragmentHostCodeName = mgr.fragmentFor(getJarFile());
        if (fragmentHostCodeName != null) {
            return fragmentHostCodeName.isEmpty() ? null : fragmentHostCodeName;
        }
        try {
            fragmentHostCodeName = data().getFragmentHostCodeName();
        } catch (IllegalStateException ex) {
            fragmentHostCodeName = null;
        }
        return fragmentHostCodeName;
    }
    
    @Override
    public String getCodeNameBase() {
        String cnb = mgr.cnbFor(getJarFile());
        if (cnb != null) {
            return cnb;
        }
        return data().getCodeNameBase();
    }
    
    @Override
    public int getCodeNameRelease() {
        return data().getCodeNameRelease();
    }
    
    public @Override String[] getProvides() {
        return data().getProvides();
    }
    /** Test whether the module provides a given token or not. 
     * @since JST-PENDING again used from NbProblemDisplayer
     */

    public final boolean provides(String token) {
        String[] provides = getProvides();
        if (provides == null) {
            return false;
        }
        for (int i = 0; i < provides.length; i++) {
            if (provides[i].equals(token)) {
                return true;
            }
        }
        return false;
    }
    
    @Override
    public Set<Dependency> getDependencies() {
        return new HashSet<Dependency>(Arrays.asList(getDependenciesArray()));
    }
    public final Dependency[] getDependenciesArray() {
        Dependency[] dependenciesA;
        try {
            dependenciesA = data().getDependencies();
        } catch (IllegalStateException ex) {
            dependenciesA = null;
        }
        return dependenciesA == null ? new Dependency[0] : dependenciesA;
    }
    
    @Override
    public SpecificationVersion getSpecificationVersion() {
        return data().getSpecificationVersion();
    }

    @Override
    public String getImplementationVersion() {
        return data().getImplementationVersion();
    }

    @Override
    public String getBuildVersion() {
        return data().getBuildVersion();
    }
    
    
    
    public @Override boolean owns(Class<?> clazz) {
        ClassLoader cl = clazz.getClassLoader();
        if (cl instanceof Util.ModuleProvider) {
            return ((Util.ModuleProvider) cl).getModule() == this;
        }
        if (cl != classloader) {
            return false;
        }
        String _codeName = findClasspathModuleCodeName(clazz);
        if (_codeName != null) {
            return _codeName.equals(getCodeName());
        }
        return true// not sure...
    }
    
    static String findClasspathModuleCodeName(Class<?> clazz) {
        // #157798: in JNLP or otherwise classpath mode, all modules share a CL.
        CodeSource src = clazz.getProtectionDomain().getCodeSource();
        if (src != null) {
            try {
                URL loc = src.getLocation();
                if (loc.toString().matches(".+\\.jar")) {
                    // URLClassLoader inconsistency.
                    loc = new URL("jar:" + loc + "!/");
                }
                URL manifest = new URL(loc, "META-INF/MANIFEST.MF");
                InputStream is = manifest.openStream();
                try {
                    return new Manifest(is).getMainAttributes().getValue("OpenIDE-Module");
                } finally {
                    is.close();
                }
            } catch (IOException x) {
                Logger.getLogger(Module.class.getName()).log(Level.FINE, null, x);
            }
        }
        return null;
    }
    
    /** Get all packages exported by this module to other modules.
     * @return a list (possibly empty) of exported packages, or null to export everything
     * @since org.netbeans.core/1 > 1.4
     * @see "#19621"
     */

    public PackageExport[] getPublicPackages() {
        return data().getPublicPackages();
    }
    
    /** Checks whether we use friends attribute and if so, then
     * whether the name of module is listed there.
     */

    boolean isDeclaredAsFriend (Module module) {
        Set<String> friendNames = data().getFriendNames();
        if (friendNames == null) {
            return true;
        }
        return friendNames.contains(module.getCodeNameBase());
    }
    
    /** Parse information from the current manifest.
     * Includes code name, specification version, and dependencies.
     * If anything is in an invalid format, throws an exception with
     * some kind of description of the problem.
     */

    protected void parseManifest() throws InvalidException {
        data();
    }


    /** Get all JARs loaded by this module.
     * Includes the module itself, any locale variants of the module,
     * any extensions specified with Class-Path, any locale variants
     * of those extensions.
     * The list will be in classpath order (patches first).
     * Currently the temp JAR is provided in the case of test modules, to prevent
     * sporadic ZIP file exceptions when background threads (like Java parsing) tries
     * to open libraries found in the library path.
     * JARs already present in the classpath are <em>not</em> listed.
     * @return a list of JARs
     */

    public abstract List<File> getAllJars();

    /** Is this module supposed to be easily reloadable?
     * If so, it is suitable for testing inside the IDE.
     * Controls whether a copy of the JAR file is made before
     * passing it to the classloader, which can affect locking
     * and refreshing of the JAR.
     */

    public boolean isReloadable() {
        return reloadable;
    }
    
    /** Set whether this module is supposed to be reloadable.
     * Has no immediate effect, only impacts what happens the
     * next time it is enabled (after having been disabled if
     * necessary).
     * Must be called from within a write mutex.
     * @param r whether the module should be considered reloadable
     */

    public abstract void setReloadable(boolean r);

    /** Reload this module. Access from ModuleManager.
     * If an exception is thrown, the module is considered
     * to be in an invalid state.
     * @since JST-PENDING: needed from ModuleSystem
     */

    public abstract void reload() throws IOException;
    
    // impl of ModuleInfo method
    public @Override ClassLoader getClassLoader() throws IllegalArgumentException {
        if (!enabled) {
            throw new IllegalArgumentException("Not enabled: " + getCodeNameBase()); // NOI18N
        }
        assert classloader != null : "Should have had a non-null loader for " + this;
        return classloader;
    }

    // Access from ModuleManager:
    /** Turn on the classloader. Passed a list of parent modules to use.
     * The parents should already have had their classloaders initialized.
     */

    protected abstract void classLoaderUp(Set<Module> parents) throws IOException;

    /** Turn off the classloader and release all resources. */
    protected abstract void classLoaderDown();
    /** Should be called after turning off the classloader of one or more modules & GC'ing. */
    protected abstract void cleanup();
    
    /** Notify the module that it is being deleted. */
    protected abstract void destroy();
    
    /**
     * Fixed modules are treated differently.
     * @see FixedModule
     */

    public abstract boolean isFixed();
    
    /** Get the JAR this module is packaged in.
     * May be null for modules installed specially, e.g.
     * automatically from the classpath.
     * @see #isFixed
     */

    public File getJarFile() {
        return null;
    }

    /** Get the JAR manifest.
     * Should never be null, even if disabled.
     * Might change if a module is reloaded.
     * It is not guaranteed that change events will be fired
     * for changes in this property.
     */

    public abstract Manifest getManifest();

    /**
     * Release memory storage for the JAR manifest, if applicable.
     */

    public void releaseManifest() {}
    
    /** Get a set of {@link org.openide.modules.Dependency} objects representing missed dependencies.
     * This module is examined to see
     * why it would not be installable.
     * If it is enabled, there are no problems.
     * If it is in fact installable (possibly only
     * by also enabling some other managed modules which are currently disabled), and
     * all of its non-module dependencies are met, the returned set will be empty.
     * Otherwise it will contain a list of reasons why this module cannot be installed:
     * non-module dependencies which are not met; and module dependencies on modules
     * which either do not exist in the managed set, or are the wrong version,
     * or themselves cannot be installed
     * for some reason or another (which may be separately examined).
     * Note that in the (illegal) situation of two or more modules forming a cyclic
     * dependency cycle, none of them will be installable, and the missing dependencies
     * for each will be stated as the dependencies on the others. Again other modules
     * dependent on modules in the cycle will list failed dependencies on the cyclic modules.
     * Missing package dependencies are not guaranteed to be reported unless an install
     * of the module has already been attempted, and failed due to them.
     * The set may also contain {@link InvalidException}s representing known failures
     * of the module to be installed, e.g. due to classloader problems, missing runtime
     * resources, or failed ad-hoc dependencies. Again these are not guaranteed to be
     * reported unless an install has already been attempted and failed due to them.
     */

    public Set<Object> getProblems() { // cannot use Union2<Dependency,InvalidException> without being binary-incompatible
        if (! isValid()) throw new IllegalStateException("Not valid: " + this); // NOI18N
        if (isEnabled()) return Collections.emptySet();
        Set<Object> problems = new HashSet<Object>();
        for (Union2<Dependency,InvalidException> problem : mgr.missingDependencies(this)) {
            if (problem.hasFirst()) {
                problems.add(problem.first());
            } else {
                problems.add(problem.second());
            }
        }
        return problems;
    }
    
    // Access from ChangeFirer:
    final void firePropertyChange0(String prop, Object old, Object nue) {
        if (Util.err.isLoggable(Level.FINE)) {
            Util.err.log(Level.FINE, "Module.propertyChange: {0} {1}: {2} -> {3}"new Object[]{this, prop, old, nue});
        }
        firePropertyChange(prop, old, nue);
    }
    
    /** Get the history object representing what has happened to this module before.
     * @see <a href="@org-netbeans-core-startup@/org/netbeans/core/startup/ModuleHistory.html">ModuleHistory</a>
     */

    public final Object getHistory() {
        return history;
    }

    /** Finds out if a module has been assigned with a specific start level.
     * Start level is only useful for OSGi bundles. Otherwise it is always zero.
     * 
     * @return -1, if no specific level is assigned, non-negative integer if so
     * @since 2.43
     */

    public final int getStartLevel() {
        return getStartLevelImpl();
    }
    
    int getStartLevelImpl() {
        return -1;
    }
    
    /** String representation for debugging. */
    public @Override String toString() {
        String s = "Module:" + getCodeNameBase(); // NOI18N
        if (!isValid()) s += "[invalid]"// NOI18N
        return s;
    }

    /** Locates resource in this module. May search only the main JAR
     * of the module (which is what it does in case of OSGi bundles). 
     * Should be as lightweight as possible - e.g. if it is OK to not
     * initialize something in the module while performing this method,
     * the something should not be initialized (e.g. OSGi bundles are
     * not resolved).
     * 
     * @param resources path to the resources we are looking for
     * @since 2.49
     */

    public Enumeration<URL> findResources(String resources) {
        try { // #149136
            ClassLoader cl = getClassLoader();

            if (cl instanceof ProxyClassLoader) {
                return ((ProxyClassLoader) cl).findResources(resources);
            }
            //TODO: other ClassLoaders - what can we expect here? can fallback to getResources for JVM classloaders, and nothing else should be here?
            throw new IllegalStateException("Unexpected ClassLoader: " + cl + ".");
        } catch (Exception x) {
            Exceptions.printStackTrace(x);
            return Enumerations.empty();
        }
    }

    /** To be overriden to empty in FixedModule & co. */
    void refineDependencies(Set<Dependency> dependencies) {
        // Permit the concrete installer to make some changes:
        mgr.refineDependencies(this, dependencies);
    }

    void registerCoveredPackages(Set<String> known) {
        data().registerCoveredPackages(known);
    }

    Set<String> getCoveredPackages() {
        return data().getCoveredPackages();
    }

    /** Is this module a wrapper around OSGi?
     * @return true, if the module is build around OSGi
     * @since 2.51
     */

    public final boolean isNetigso() {
        return isNetigsoImpl();
    }
    
    boolean isNetigsoImpl() {
        return false;
    }

    final void assignInstrumentation(NbInstrumentation agent) {
        instr = agent;
    }

    void unregisterInstrumentation() {
        NbInstrumentation.unregisterAgent(instr);
    }
    
    /**
     * Release references to the ClassLoader. Package-private for now as only (?) FixedModule
     * should retain the CL instance.
     */

    void releaseClassLoader() {
       this.classloader = null
    }

    /** Struct representing a package exported from a module.
     * @since org.netbeans.core/1 > 1.4
     * @see Module#getPublicPackages
     */

    public static final class PackageExport {
        /** Package to export, in the form <code>org/netbeans/modules/foo/</code>. */
        public final String pkg;
        /** If true, export subpackages also. */
        public final boolean recursive;
        /** Create a package export struct with the named parameters. */
        public PackageExport(String pkg, boolean recursive) {
            this.pkg = pkg;
            this.recursive = recursive;
        }
        public @Override String toString() {
            return "PackageExport[" + pkg + (recursive ? "**/" : "") + "]"// NOI18N
        }
        public @Override boolean equals(Object obj) {
            if (!(obj instanceof PackageExport)) {
                return false;
            }
            final PackageExport other = (PackageExport) obj;
            return pkg.equals(other.pkg) && recursive == other.recursive;
        }
        public @Override int hashCode() {
            return pkg.hashCode();
        }
        
        static void write(DataOutput dos, PackageExport[] arr) throws IOException {
            if (arr == null) {
                dos.writeInt(0);
                return;
            }
            dos.writeInt(arr.length);
            for (PackageExport pe : arr) {
                dos.writeUTF(pe.pkg);
                dos.writeBoolean(pe.recursive);
            }
        }
        
        static PackageExport[] read(DataInput is) throws IOException {
            int cnt = is.readInt();
            if (cnt == 0) {
                return null;
            }
            PackageExport[] arr = new PackageExport[cnt];
            for (int i = 0; i < cnt; i++) {
                String pkg = is.readUTF();
                boolean recursive = is.readBoolean();
                arr[i] = new PackageExport(pkg, recursive);
            }
            return arr;
        }
    }
}

Messung V0.5
C=94 H=89 G=91

¤ Dauer der Verarbeitung: 0.7 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung ist noch experimentell.