SquirrelJME/SquirrelJME

View on GitHub
emulators/emulator-base/src/main/java/cc/squirreljme/emulator/vm/PathSuiteManager.java

Summary

Maintainability
A
0 mins
Test Coverage
// -*- Mode: Java; indent-tabs-mode: t; tab-width: 4 -*-
// ---------------------------------------------------------------------------
// SquirrelJME
//     Copyright (C) Stephanie Gawroriski <xer@multiphasicapps.net>
// ---------------------------------------------------------------------------
// SquirrelJME is under the Mozilla Public License Version 2.0.
// See license.mkd for licensing and copyright information.
// ---------------------------------------------------------------------------

package cc.squirreljme.emulator.vm;

import cc.squirreljme.jvm.suite.SuiteUtils;
import cc.squirreljme.vm.InMemoryClassLibrary;
import cc.squirreljme.vm.VMClassLibrary;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import net.multiphasicapps.zip.streamreader.ZipStreamReader;

/**
 * This is a suite manager which uses the filesystem.
 *
 * @since 2018/12/08
 */
public final class PathSuiteManager
    implements VMSuiteManager
{
    /** The base lib directory. */
    protected final Path libpath;
    
    /** Cache of loaded libraries. */
    private final Map<String, VMClassLibrary> _cache =
        new HashMap<>();
    
    /**
     * Initializes the suite manager.
     *
     * @param __lp The library path.
     * @throws NullPointerException On null arguments.
     * @since 2018/12/09
     */
    public PathSuiteManager(Path __lp)
        throws NullPointerException
    {
        if (__lp == null)
            throw new NullPointerException("NARG");
        
        this.libpath = __lp;
    }
    
    /**
     * {@inheritDoc}
     * @since 2018/12/08
     */
    @Override
    public final String[] listLibraryNames()
    {
        // Could fail
        try
        {
            Set<String> rv = new LinkedHashSet<>();
            
            // Go through directory entries
            try (DirectoryStream<Path> dir = Files.newDirectoryStream(
                this.libpath))
            {
                for (Path p : dir)
                {
                    // Ignore directories
                    if (Files.isDirectory(p))
                        continue;
                    
                    String fn = p.getFileName().toString();
                    if (SuiteUtils.isAny(fn))
                        rv.add(fn);
                }
            }
            
            return rv.<String>toArray(new String[rv.size()]);
        }
        
        // Was not found, ignore
        catch (NoSuchFileException e)
        {
            return new String[0];
        }
        
        // Could not load!
        catch (IOException e)
        {
            e.printStackTrace();
            
            return new String[0];
        }
    }
    
    /**
     * {@inheritDoc}
     * @since 2023/12/18
     */
    @Override
    public int libraryId(VMClassLibrary __lib)
        throws IllegalArgumentException, NullPointerException
    {
        if (__lib == null)
            throw new NullPointerException("NARG");
        
        Map<String, VMClassLibrary> cache = this._cache;
        synchronized (cache)
        {
            // The library must have been previously loaded first
            if (!cache.values().contains(__lib))
                throw new IllegalArgumentException(
                    "Unknown library: " + __lib);
            
            Path path = __lib.path();
            return (path != null ? path.hashCode() : __lib.name().hashCode());
        }
    }
    
    /**
     * {@inheritDoc}
     * @since 2018/12/08
     */
    @Override
    public final VMClassLibrary loadLibrary(String __s)
        throws NullPointerException
    {
        if (__s == null)
            throw new NullPointerException("NARG");
        
        Map<String, VMClassLibrary> cache = this._cache;
        synchronized (cache)
        {
            VMClassLibrary rv = cache.get(__s);
            if (rv != null)
                return rv;
            
            // Pre-cached to not exist
            if (cache.containsKey(__s))
                return null;
            
            // Open file and stream the ZIP
            try (InputStream in = Files.newInputStream(
                this.libpath.resolve(__s), StandardOpenOption.READ);
                ZipStreamReader zsr = new ZipStreamReader(in))
            {
                cache.put(__s, (rv = InMemoryClassLibrary.loadZip(__s, zsr)));
                return rv;
            }
            
            // Does not exist, stop
            catch (NoSuchFileException e)
            {
                cache.put(__s, null);
                return null;
            }
            
            // Exists but it is not valid, verbosely fail
            catch (IOException e)
            {
                e.printStackTrace();
                
                cache.put(__s, null);
                return null;
            }
        }
    }
}