SquirrelJME/SquirrelJME

View on GitHub
modules/debug-jdwp-vm-host/src/main/java/cc/squirreljme/jdwp/host/JDWPHostState.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.jdwp.host;

import cc.squirreljme.jdwp.host.views.JDWPView;
import cc.squirreljme.jdwp.host.views.JDWPViewKind;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;

/**
 * This contains the complete state for the debugging instance.
 *
 * @since 2021/03/13
 */
public final class JDWPHostState
{
    /** References to everything the debugger knows about. */
    public final JDWPHostLinker<Object> items =
        new JDWPHostLinker<>(Object.class);
    
    /** The binding used. */
    private final Reference<JDWPHostBinding> _binding;
    
    /** The views that are available. */
    private final JDWPView[] _views =
        new JDWPView[JDWPViewKind.values().length];
    
    /** Has this been latched? */
    private volatile boolean _latchStart;
    
    /**
     * Initializes the state.
     * 
     * @param __binding The binding used.
     * @throws NullPointerException On null arguments.
     * @since 2021/04/10
     */
    JDWPHostState(Reference<JDWPHostBinding> __binding)
        throws NullPointerException
    {
        if (__binding == null)
            throw new NullPointerException("NARG");
        
        this._binding = __binding;
    }
    
    /**
     * Latches onto whether this is the first thread being added.
     *
     * @return If this is the first thread, this method only
     * returns {@code true} once.
     * @since 2024/01/21
     */
    public boolean latchFirstThread()
    {
        synchronized (this)
        {
            // Once set, this always returns false
            if (this._latchStart)
                return false;
            
            // Latch and return true, so we cannot call again
            this._latchStart = true;
            return true;
        }
    }
    
    /**
     * Returns the view of the given type.
     * 
     * @param <V> The type to view.
     * @param __type The type to view.
     * @param __kind The kind of viewer to use.
     * @return The view for the given type.
     * @throws NullPointerException On null arguments.
     * @since 2021/04/10
     */
    public final <V extends JDWPView> V view(Class<V> __type,
        JDWPViewKind __kind)
        throws NullPointerException
    {
        if (__type == null || __kind == null)
            throw new NullPointerException("NARG");
        
        // Use a pre-cached view if available
        JDWPView[] views = this._views;
        JDWPView view = views[__kind.ordinal()];
        if (view != null)
            return __type.cast(view);
        
        // Obtain the view for this kind of object
        view = this.__binding().debuggerView(__type, __kind,
            new WeakReference<>(this));
        
        /* {@squirreljme.error AG0m The binding does not know about this kind
        of view? (The kind)} */
        if (view == null)
            throw new IllegalStateException("AG0m " + __kind);
        
        // Cache for later and use it now
        views[__kind.ordinal()] = view;
        return __type.cast(view);
    }
    
    /**
     * Returns the used binding.
     * 
     * @return The binding used.
     * @throws IllegalStateException If the binding was GCed.
     * @since 2021/04/10
     */
    final JDWPHostBinding __binding()
        throws IllegalStateException
    {
        /* {@squirreljme.error AG0l The Binding was GCed.} */
        JDWPHostBinding rv = this._binding.get();
        if (rv == null)
            throw new IllegalStateException("AG0l");
        
        return rv;
    }
}