Search in sources :

Example 1 with AnnotationMirror

use of com.laytonsmith.PureUtilities.ClassLoading.ClassMirror.AnnotationMirror in project CommandHelper by EngineHub.

the class ExtensionManager method Cache.

public static void Cache(File extCache, Class... extraClasses) {
    // We will only cache on Windows, as Linux doesn't natively lock
    // files that are in use. Windows prevents any modification, making
    // it harder for server owners on Windows to update the jars.
    boolean onWindows = (OSUtils.GetOS() == OSUtils.OS.WINDOWS);
    if (!onWindows) {
        return;
    }
    // Create the directory if it doesn't exist.
    extCache.mkdirs();
    // cleanup wasn't successful on the last run.
    for (File f : extCache.listFiles()) {
        try {
            Files.delete(f.toPath());
        } catch (IOException ex) {
            Static.getLogger().log(Level.WARNING, "[CommandHelper] Could not delete loose file " + f.getAbsolutePath() + ": " + ex.getMessage());
        }
    }
    // The cache, cd and dcl here will just be thrown away.
    // They are only used here for the purposes of discovering what a given
    // jar has to offer.
    ClassDiscoveryCache cache = new ClassDiscoveryCache(CommandHelperFileLocations.getDefault().getCacheDirectory());
    cache.setLogger(Static.getLogger());
    DynamicClassLoader dcl = new DynamicClassLoader();
    ClassDiscovery cd = new ClassDiscovery();
    cd.setClassDiscoveryCache(cache);
    cd.addDiscoveryLocation(ClassDiscovery.GetClassContainer(ExtensionManager.class));
    for (Class klazz : extraClasses) {
        cd.addDiscoveryLocation(ClassDiscovery.GetClassContainer(klazz));
    }
    // Look in the given locations for jars, add them to our class discovery.
    List<File> toProcess = new ArrayList<>();
    for (File location : locations) {
        toProcess.addAll(getFiles(location));
    }
    // Load the files into the discovery mechanism.
    for (File file : toProcess) {
        if (!file.canRead()) {
            continue;
        }
        URL jar;
        try {
            jar = file.toURI().toURL();
        } catch (MalformedURLException ex) {
            Static.getLogger().log(Level.SEVERE, null, ex);
            continue;
        }
        dcl.addJar(jar);
        cd.addDiscoveryLocation(jar);
    }
    cd.setDefaultClassLoader(dcl);
    // Loop thru the found lifecycles, copy them to the cache using the name
    // given in the lifecycle. If more than one jar has the same internal
    // name, the filename will be given a number.
    Set<File> done = new HashSet<>();
    Map<String, Integer> namecount = new HashMap<>();
    // use their internal name.
    for (ClassMirror<? extends AbstractExtension> extmirror : cd.getClassesWithAnnotationThatExtend(MSExtension.class, AbstractExtension.class)) {
        if (extmirror.equals(new ClassMirror<>(AbstractExtension.class))) {
            continue;
        }
        AnnotationMirror plug = extmirror.getAnnotation(MSExtension.class);
        URL plugURL = extmirror.getContainer();
        // Get the internal name that this extension exposes.
        if (plugURL != null && plugURL.getPath().endsWith(".jar")) {
            File f;
            try {
                f = new File(URLDecoder.decode(plugURL.getFile(), "UTF8"));
            } catch (UnsupportedEncodingException ex) {
                Logger.getLogger(ExtensionManager.class.getName()).log(Level.SEVERE, null, ex);
                continue;
            }
            // Skip extensions that originate from commandhelpercore.
            if (plugURL.equals(ClassDiscovery.GetClassContainer(ExtensionManager.class))) {
                done.add(f);
                continue;
            }
            // Skip files already processed.
            if (done.contains(f)) {
                CHLog.GetLogger().Log(CHLog.Tags.EXTENSIONS, LogLevel.WARNING, f.getAbsolutePath() + " contains more than one extension" + " descriptor. Bug someone about it!", Target.UNKNOWN);
                continue;
            }
            done.add(f);
            String name = plug.getValue("value").toString();
            // lets track and rename them using a number scheme.
            if (namecount.containsKey(name.toLowerCase())) {
                int i = namecount.get(name.toLowerCase());
                name += "-" + i;
                namecount.put(name.toLowerCase(), i++);
                CHLog.GetLogger().Log(CHLog.Tags.EXTENSIONS, LogLevel.WARNING, f.getAbsolutePath() + " contains a duplicate internally" + " named extension (" + name + "). Bug someone" + " about it!", Target.UNKNOWN);
            } else {
                namecount.put(name.toLowerCase(), 1);
            }
            // Rename the jar to use the plugin's internal name and
            // copy it into the cache.
            File newFile = new File(extCache, name.toLowerCase() + ".jar");
            try {
                Files.copy(f.toPath(), newFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
            } catch (IOException ex) {
                Static.getLogger().log(Level.SEVERE, "Could not copy '" + f.getName() + "' to cache: " + ex.getMessage());
            }
        }
    }
    Set<ClassMirror<?>> classes = cd.getClassesWithAnnotation(api.class);
    // Now process @api annotated extensions, ignoring ones already processed.
    for (ClassMirror klass : classes) {
        URL plugURL = klass.getContainer();
        if (plugURL != null && plugURL.getPath().endsWith(".jar")) {
            File f;
            try {
                f = new File(URLDecoder.decode(plugURL.getFile(), "UTF8"));
            } catch (UnsupportedEncodingException ex) {
                Logger.getLogger(ExtensionManager.class.getName()).log(Level.SEVERE, null, ex);
                continue;
            }
            // Skip files already processed.
            if (done.contains(f)) {
                continue;
            }
            // No special processing needed.
            if (cd.doesClassExtend(klass, Event.class) || cd.doesClassExtend(klass, Function.class)) {
                // We're processing it here instead of above, complain about it.
                CHLog.GetLogger().Log(CHLog.Tags.EXTENSIONS, LogLevel.WARNING, f.getAbsolutePath() + " is an old-style extension!" + " Bug the author to update it to the new extension system!", Target.UNKNOWN);
                // Only process this file once.
                done.add(f);
                File newFile = new File(extCache, "oldstyle-" + f.getName());
                try {
                    Files.copy(f.toPath(), newFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
                } catch (IOException ex) {
                    Static.getLogger().log(Level.SEVERE, "Could not copy '" + f.getName() + "' to cache: " + ex.getMessage());
                }
            }
        }
    }
    // Shut down the original dcl to "unlock" the processed jars.
    // The cache and cd instances will just fall into oblivion.
    dcl.destroy();
    // Explicit call. Without this, jar files won't actually get unlocked on
    // Windows. Of course, this is hit and miss, but that's fine; we tried.
    System.gc();
}
Also used : DynamicClassLoader(com.laytonsmith.PureUtilities.ClassLoading.DynamicClassLoader) MalformedURLException(java.net.MalformedURLException) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) ClassMirror(com.laytonsmith.PureUtilities.ClassLoading.ClassMirror.ClassMirror) URL(java.net.URL) CFunction(com.laytonsmith.core.constructs.CFunction) Function(com.laytonsmith.core.functions.Function) HashSet(java.util.HashSet) UnsupportedEncodingException(java.io.UnsupportedEncodingException) IOException(java.io.IOException) ClassDiscovery(com.laytonsmith.PureUtilities.ClassLoading.ClassDiscovery) AnnotationMirror(com.laytonsmith.PureUtilities.ClassLoading.ClassMirror.AnnotationMirror) Event(com.laytonsmith.core.events.Event) File(java.io.File) ClassDiscoveryCache(com.laytonsmith.PureUtilities.ClassLoading.ClassDiscoveryCache)

Aggregations

ClassDiscovery (com.laytonsmith.PureUtilities.ClassLoading.ClassDiscovery)1 ClassDiscoveryCache (com.laytonsmith.PureUtilities.ClassLoading.ClassDiscoveryCache)1 AnnotationMirror (com.laytonsmith.PureUtilities.ClassLoading.ClassMirror.AnnotationMirror)1 ClassMirror (com.laytonsmith.PureUtilities.ClassLoading.ClassMirror.ClassMirror)1 DynamicClassLoader (com.laytonsmith.PureUtilities.ClassLoading.DynamicClassLoader)1 CFunction (com.laytonsmith.core.constructs.CFunction)1 Event (com.laytonsmith.core.events.Event)1 Function (com.laytonsmith.core.functions.Function)1 File (java.io.File)1 IOException (java.io.IOException)1 UnsupportedEncodingException (java.io.UnsupportedEncodingException)1 MalformedURLException (java.net.MalformedURLException)1 URL (java.net.URL)1 ArrayList (java.util.ArrayList)1 HashMap (java.util.HashMap)1 HashSet (java.util.HashSet)1