Package net.jcores.jre

Source Code of net.jcores.jre.CommonCore

/*
* CommonCore.java
*
* Copyright (c) 2010, Ralf Biedert All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer. 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.
*
* Neither the name of the author nor the names of its contributors may be used to endorse or
* promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
* 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
* COPYRIGHT OWNER OR 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.
*
*/
package net.jcores.jre;

import static net.jcores.jre.CoreKeeper.$;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicReference;
import java.util.logging.Level;

import net.jcores.jre.annotations.AttentionWithClassloaders;
import net.jcores.jre.annotations.Beta;
import net.jcores.jre.annotations.SupportsOption;
import net.jcores.jre.cores.Core;
import net.jcores.jre.cores.CoreNumber;
import net.jcores.jre.cores.CoreObject;
import net.jcores.jre.cores.adapter.ListAdapter;
import net.jcores.jre.cores.commons.CommonAlgorithmic;
import net.jcores.jre.cores.commons.CommonNet;
import net.jcores.jre.cores.commons.CommonSys;
import net.jcores.jre.cores.commons.CommonUI;
import net.jcores.jre.interfaces.functions.F0;
import net.jcores.jre.interfaces.functions.F0R;
import net.jcores.jre.managers.Manager;
import net.jcores.jre.managers.ManagerClass;
import net.jcores.jre.managers.ManagerDebugGUI;
import net.jcores.jre.managers.ManagerDeveloperFeedback;
import net.jcores.jre.managers.ManagerExecution;
import net.jcores.jre.managers.ManagerLogging;
import net.jcores.jre.options.KillSwitch;
import net.jcores.jre.options.MessageType;
import net.jcores.jre.options.Option;
import net.jcores.jre.utils.Async;
import net.jcores.jre.utils.Async.Queue;
import net.jcores.jre.utils.internal.Options;
import net.jcores.jre.utils.internal.Reporter;
import net.jcores.jre.utils.internal.structures.ProfileInformation;
import net.jcores.jre.utils.map.ConcurrentMapUtil;
import net.jcores.jre.utils.map.MapUtil;
import net.xeoh.nexus.DefaultNexus;
import net.xeoh.nexus.InternalService;
import net.xeoh.nexus.Nexus;

/**
* The common core is a notso-singleton object shared by all created {@link Core} instances of the current class loader.
* It is mainly a cache, contains helper and utility
* methods and takes care of the {@link Manager} objects. For example, to but the current thread
* to sleep (without the ugly try/catch), you would write:<br/>
* <br/>
*
* <code>$.sys.sleep(1000);</code> <br/>
* <br/>
*
* Methods and object commonly required by the other cores. All methods in here are (and must be!)
* thread safe. While most methods (like <code>async()</code>, <code>box()</code>, <code>clone()</code>, ...) are safe
* to use in any application, there are a few methods (like <code>manager()</code>, <code>nexus()</code>,
* <code>log()</code>) which should be used with care in
* multi-classloader-applications like application servers. While they will work in local parts of the
* code they usually fail to share state between remote parts (e.g., one web application could not
* register an object with <code>nexus()</code> another web application could see). Methods marked
* with {@link AttentionWithClassloaders} are such candidates. You can still use them in big apps,
* but you should know what you are doing.
*
* @author Ralf Biedert
* @since 1.0
*/
public class CommonCore {
    /** Stores error reports */
    private final Reporter reporter = new Reporter(this);

    /** Stores our managers and possibly application services */
    private final Nexus nexus = new DefaultNexus();

    /** Random variable */
    private final Random random = new Random();

    /** Keeps the profile information */
    private ProfileInformation profileInformation;

    /** Executes commands */
    private ManagerExecution executionManager;

    /** Method to clone objects */
    private Method cloneMethod;

    /** Common system utilities */
    public final CommonSys sys = new CommonSys(this);

    /** Common algorithmic utilities */
    public final CommonAlgorithmic alg = new CommonAlgorithmic(this);

    /** Common ui utilities */
    public final CommonUI ui = new CommonUI(this);

    /** Common net utilities */
    public final CommonNet net = new CommonNet(this);

    /** The ID of this CommonCore */
    protected final String id;

    /**
     * Constructs the common core.
     */
    protected CommonCore() {
        // Register managers we know
        manager(ManagerExecution.class, new ManagerExecution());
        manager(ManagerClass.class, new ManagerClass());
        manager(ManagerDeveloperFeedback.class, new ManagerDeveloperFeedback());
        manager(ManagerDebugGUI.class, new ManagerDebugGUI());
        manager(ManagerLogging.class, new ManagerLogging());

        try {
            this.cloneMethod = Object.class.getDeclaredMethod("clone");
            this.cloneMethod.setAccessible(true);
        } catch (Exception e) {
            report(MessageType.EXCEPTION, "Unable to get cloning method for objects. $.clone() will not work: " + e.getMessage());
        }

        this.id = this.sys.uniqueID();
    }

    /** Updates the managers and their returned information in this core */
    protected void updateManagerInformation() {
        this.executionManager = manager(ManagerExecution.class);
        this.profileInformation = this.executionManager.getProfile();
    }

    /**
     * Executes the given function asynchronously and returns an {@link Async} object which
     * will hold the result.<br/>
     * <br/>
     *
     * Examples:
     * <ul>
     * <li><code>$.async(lookup)</code> - Performs some lookup task in the background.</li>
     * </ul>
     *
     * Single-threaded. <br/>
     * <br/>
     *
     * @param f The function to execute asynchronously on the enclosed objects.
     * @param options Supports all options {@link CommonSys}.<code>oneTime()</code> understands (esp. {@link KillSwitch}
     * ).
     * @param <R> Return type for the {@link Async} object.
     * @return An {@link Async} object that will hold the results (in an arbitrary order).
     */
    @SupportsOption(options = { KillSwitch.class })
    public <R> Async<R> async(final F0R<R> f, final Option... options) {
        final Queue<R> queue = Async.Queue();
        final Async<R> async = new Async<R>(this, queue);

        // Maybe use the executor right away?
        this.sys.oneTime(new F0() {
            @Override
            public void f() {
                try {
                    queue.add(Async.QEntry(f.f()));
                    queue.close();
                } catch (Exception e) {
                    final Options options$ = Options.$(CommonCore.this, options);
                    options$.failure(f, e, "async:exception", "General exception invoking async function.");
                    queue.close();
                }
            }
        }, 0, options);

        return async;
    }

    /**
     * Wraps number of ints and returns an Integer array.
     *
     * @since 1.0
     * @param object The numbers to wrap.
     * @return An Integer array.
     */
    public Integer[] box(int... object) {
        int i = 0;

        final Integer[] myIntegers = new Integer[object.length];
        for (int val : object)
            myIntegers[i++] = Integer.valueOf(val);

        return myIntegers;
    }

    /**
     * Wraps number of doubles and returns a Double array.
     *
     * @since 1.0
     * @param object The numbers to wrap.
     * @return An Double array.
     */
    public Double[] box(double... object) {
        int i = 0;

        final Double[] myIntegers = new Double[object.length];
        for (double val : object)
            myIntegers[i++] = Double.valueOf(val);

        return myIntegers;
    }

    /**
     * Wraps number of floats and returns a new Float array.
     *
     * @param object The numbers to wrap.
     * @return A CoreNumber wrapping the given compounds.
     */
    public Float[] box(float... object) {
        int i = 0;

        final Float[] myIntegers = new Float[object.length];
        for (float val : object)
            myIntegers[i++] = Float.valueOf(val);

        return myIntegers;
    }

    /**
     * Wraps number of longs and returns an Long array.
     *
     * @since 1.0
     * @param object The numbers to wrap.
     * @return An Integer array.
     */
    public Long[] box(long... object) {
        int i = 0;

        final Long[] myIntegers = new Long[object.length];
        for (long val : object)
            myIntegers[i++] = Long.valueOf(val);

        return myIntegers;
    }

    /**
     * Clones the given object if it is cloneable.
     *
     * @since 1.0
     * @param <T>
     * @param object The object to clone
     * @param options The supported default options.
     * @return A clone of the object, or null if the object could not be cloned.
     */
    @SuppressWarnings("unchecked")
    public <T> T clone(T object, Option... options) {
        if (!(object instanceof Cloneable)) return null;

        try {
            return (T) this.cloneMethod.invoke(object);
        } catch (Exception e) {
            Options.$(this, options).failure(object, e, "clone:unknown", "Unable to clone object.");
        }

        return null;
    }

    /**
     * Clones the given array and returns a <b>shallow</b> copy (i.e., the elements themselves
     * are the same in both arrays).
     *
     * @since 1.0
     * @param <T>
     * @param object The array to clone
     * @return A cloned (copied) array.
     */
    public <T> T[] clone(T[] object) {
        if (object == null) return null;
        return Arrays.copyOf(object, object.length);
    }

    /**
     * Returns a new and empty {@link ConcurrentMapUtil}.
     *
     * @param <K> The type of the key.
     * @param <V> The type of the value.
     * @since 1.0
     * @return Returns a new map.
     */
    public <K, V> ConcurrentMapUtil<K, V> concurrentMap() {
        return new ConcurrentMapUtil<K, V>(new ConcurrentHashMap<K, V>());
    }

    /**
     * Wraps a given map into out {@link ConcurrentMapUtil}.
     *
     * @param <K> The type of the key.
     * @param <V> The type of the value.
     * @param map The map to wrap.
     * @return Returns a wrapped map.
     */
    public <K, V> ConcurrentMapUtil<K, V> concurrentMap(ConcurrentMap<K, V> map) {
        return new ConcurrentMapUtil<K, V>(map);
    }

    /**
     * Returns a core consisting of <code>n</code> times the given object.
     *
     * @param object The object to fill the core with.
     * @param n The number of times we put the object into the core.
     * @param <T> The type of the object.
     * @since 1.0
     * @return A core of size <code>n</code> filled with the given object.
     *
     */
    public <T> CoreObject<T> create(T object, int n) {
        final ArrayList<T> list = new ArrayList<T>(n);
        for (int i = 0; i < n; i++) {
            list.add(object);
        }
        return new CoreObject<T>(this, new ListAdapter<T>(list));
    }

    /**
     * Clones the given collection and returns a <b>shallow</b> copy (i.e., the elements themselves
     * are the same in both arrays).
     *
     * @since 1.0
     * @param <T>
     * @param collection The collection to clone
     * @return A cloned (copied) collection.
     */
    public <T> Collection<T> clone(Collection<T> collection) {
        if (collection == null) return null;
        return new ArrayList<T>(collection);
    }

    /**
     * Returns the ID of this {@link CommonCore}.
     *
     * @since 1.0
     * @return The unique ID of this {@link CommonCore}.
     */
    public String coreID() {
        return this.id;
    }

    /**
     * Clones the given array and returns a <b>deep</b> copy (i.e., the elements themselves
     * are the cloned in both arrays).
     *
     * @since 1.0
     * @param <T>
     * @param object The array to clone
     * @return A cloned array.
     */
    public <T> T[] deepclone(T[] object) {
        if (object == null) return null;

        final T[] copyOf = Arrays.copyOf(object, object.length);
        for (int i = 0; i < copyOf.length; i++) {
            copyOf[i] = clone(copyOf[i]);
        }

        return copyOf;
    }

    /**
     * Returns our default jCores executor.
     *
     * @since 1.0
     * @return The default executor service.
     */
    public ManagerExecution executor() {
        return this.executionManager;
    }

    /**
     * Call this function if you want to give the jCores team runtime feedback of your
     * application. The library will then, at certain points, upload profiling and
     * execution results to improve the performance and usability. Everything stays anonymous!
     *
     * @since 1.0
     */
    @Beta
    public void feedback() {
        //
    }

    /**
     * Returns the default nexus for jCores. Do <i>not</i> use this instance
     * to manage <i>globals</i> or singletons for your application, since there might be
     * cases where two parts of your app won't see each other (e.g., different
     * classloaders). The {@link CommonCore} in jCores is merely a local <i>cache</i>, shared
     * by the stataic {@link CoreKeeper} (with some added extras), that keeps track of non-essential,
     * sharable objects which are expensive to create (like profiling information).<br/>
     * <br/>
     *
     * @since 1.0
     * @return The default {@link Nexus} used by jCores (which might be used by your
     * application as well if you know what you are doing, but keep in mind the warning above).
     */
    @AttentionWithClassloaders
    public Nexus nexus() {
        return this.nexus;
    }

    /**
     * Sets a manager of a given type, only needed for core developers.
     *
     * @param <T> Manager's type.
     * @param clazz Manager's class.
     * @param manager The actual manager to put.
     * @return Return the manager that was already in the list, if there was one, or the current manager which was also
     * set.
     */
    @AttentionWithClassloaders
    public <T extends Manager> T manager(Class<T> clazz, T manager) {
        // Perpare adding the manager to the kernel
        final Collection<InternalService<T>> services = new ArrayList<InternalService<T>>();
        services.add(new InternalService<T>(manager));

        // And add it, and update the manager information
        this.nexus.register(services);
        updateManagerInformation();

        // Eventually return the result.
        return this.nexus.get(clazz);
    }

    /**
     * Returns a manager of the given type, only needed for core developers.
     *
     * @param <T> Manager's type.
     * @param clazz Manager's class.
     * @return Returns the currently set manager.
     */
    @AttentionWithClassloaders
    public <T extends Manager> T manager(Class<T> clazz) {
        return this.nexus.get(clazz);
    }

    /**
     * Returns a new and empty (hash) {@link MapUtil}.
     *
     * @param <K> The type of the key.
     * @param <V> The type of the value.
     * @since 1.0
     * @return Returns a new map.
     */
    public <K, V> MapUtil<K, V> map() {
        return new MapUtil<K, V>(new HashMap<K, V>());
    }

    /**
     * Wraps a given map into out {@link MapUtil}.
     *
     * @param <K> The type of the key.
     * @param <V> The type of the value.
     * @param map The map to wrap.
     * @return Returns a wrapped map.
     */
    public <K, V> MapUtil<K, V> map(Map<K, V> map) {
        return new MapUtil<K, V>(map);
    }

    /**
     * Returns a new (linked) {@link List} when the number of elements to
     * store is not known.
     *
     * @since 1.0
     * @param <T> The type of the list.
     * @return The new list.
     */
    public <T> List<T> list() {
        return new LinkedList<T>();
    }

    /**
     * Returns a new (array) {@link List} when the number of elements to store is
     * approximately known.
     *
     * @since 1.0
     * @param <T> The type of the list.
     * @param n The approximate number of elements to store.
     * @return The new list.
     */
    public <T> List<T> list(int n) {
        return new ArrayList<T>(n);
    }

    /**
     * Logs the given string. This method might, but is not required, to use the official Java logging
     * facilities.
     *
     * @param string The string to log.
     * @param level Log level to use.
     */
    @AttentionWithClassloaders
    public void log(String string, Level level) {
        this.manager(ManagerLogging.class).handler().log(string, level);
    }

    /**
     * Measures how long the execution of the given function took. The result will be returned in nanoseconds.
     *
     * @param f The function to execute.
     * @return The elapsed time in nanoseconds.
     */
    public long measure(F0 f) {
        final long start = System.nanoTime();
        f.f();
        final long end = System.nanoTime();
        return end - start;
    }

    /**
     * Measures how long the execution of the given function took <code>n</code> times. A CoreNumber object will be
     * returned with the results.
     *
     * @param f The function to execute.
     * @param n The number of times <code>f</code> should be executed.
     * @return A {@link CoreNumber} object with the elapsed times in nanoseconds.
     */
    @SuppressWarnings("boxing")
    public CoreNumber measure(F0 f, int n) {
        final List<Long> results = $.list(n);

        for (int i = 0; i < n; i++) {
            results.add(measure(f));
        }

        return CoreKeeper.$(results).as(CoreNumber.class);
    }

    /**
     * Returns the profiling information gathered at startup. Only required internally.
     *
     * @return The current profile information.
     */
    public ProfileInformation profileInformation() {
        return this.profileInformation;
    }

    /**
     * Creates a CoreNumber object with numbers ranging from 0 (inclusive) up to <code>end</code> (exclusive).
     *
     * @param end The last number (exclusive).
     * @return A core number object.
     */
    public CoreNumber range(int end) {
        return range(0, end, 1);
    }

    /**
     * Creates a CoreNumber object with the given <code>start</code> (inclusive) and <code>end</code> (exclusive) and a
     * stepping of +-1 (depending on whether start is smaller or larger than end).
     *
     * @param from The first number (inclusive)
     * @param end The last number (exclusive).
     * @return A core number object.
     */
    public CoreNumber range(int from, int end) {
        return range(from, end, from <= end ? 1 : -1);
    }

    /**
     * Creates a CoreNumber object with the given <code>start</code> (inclusive), <code>end</code> (exclusive) and
     * stepping.
     *
     * @param from The first number (inclusive)
     * @param end The last number (exclusive).
     * @param stepping The stepping
     *
     * @return A core number object.
     */
    public CoreNumber range(int from, int end, int stepping) {
        // FIXME: Stepping problems
        final int rval[] = new int[Math.abs((end - from) / stepping)];
        int ptr = 0;

        if (from <= end) {
            for (int i = from; i < end; i += stepping) {
                rval[ptr++] = i;
            }
        } else {
            for (int i = from; i > end; i += stepping) {
                rval[ptr++] = i;
            }
        }

        return new CoreNumber(this, box(rval));
    }

    /**
     * Returns a new, empty {@link AtomicReference}.
     *
     * @since 1.0
     * @param <T> The type of the reference.
     * @return A new, empty reference.
     */
    public <T> AtomicReference<T> reference() {
        return new AtomicReference<T>();
    }

    /**
     * Returns a new, already set {@link AtomicReference}.
     *
     * @since 1.0
     * @param object The initial value.
     * @param <T> The type of the reference.
     * @return A new reference.
     */
    public <T> AtomicReference<T> reference(T object) {
        return new AtomicReference<T>(object);
    }

    /**
     * Reports the problem to our internal problem queue, only used by core developers. Use report() for all
     * internal error and problem reporting and use log() for user requested
     * logging.
     *
     * @param type Type of the message.
     * @param problem Problem description.
     */
    public void report(MessageType type, String problem) {
        this.reporter.record(problem);
    }

    /**
     * Prints all known problem reports to the console. This is the end-user
     * version (which means, <i>you</i> can use it) to print what went wrong during
     * core operation. See the console for output.
     */
    public void report() {
        this.reporter.printRecords();
    }

    /**
     * Returns our shared {@link Random} object, initialized some time ago.
     *
     * @return The initialized random object.
     */
    public Random random() {
        return this.random;
    }

    /**
     * Unboxes a number of Integers.
     *
     * @param object The numbers to unbox.
     * @return An int array.
     */
    @SuppressWarnings("boxing")
    public int[] unbox(Integer... object) {
        int i = 0;

        final int[] myIntegers = new int[object.length];
        for (int val : object)
            myIntegers[i++] = val;

        return myIntegers;
    }

    /**
     * Returns jCores' version, for example <code>1.0.4-201108111256</code>. The version string will
     * always consist of two parts: the actual version (with usually a major, minor and revision part),
     * as well as a dash-separated build number.
     *
     * @return The current version.
     */
    public String version() {
        return $(getClass().getResourceAsStream("jcores.version")).text().split("\n").hashmap().get("build");
    }

    /**
     * Requests a number of CPUs. The system will check how many CPUs are available
     * and allocate up to <code>request</code> units. The number of allocated CPUs is
     * returned.<br/>
     * <br/>
     *
     * This function is only used internally. Also note that it is essential to call <code>releaseCPUs</code> after the
     * application stopped using them.
     *
     * @param request The number of CPUs to request.
     *
     * @return The actual number of CPUs available.
     */
    public int requestCPUs(int request) {
        // When looking at our benchmarks, it seems this does not speed up things, see Issue #12.
        return Math.min(profileInformation().numCPUs, request);

        /*
         * synchronized (this.freeCPUs) {
         * final int free = this.freeCPUs.get();
         *
         * // No free CPUs means to party
         * if(free == 0) return 0;
         *
         * // More requested than free, return what we have
         * if(request > free) {
         * this.freeCPUs.set(0);
         * return free;
         * }
         *
         * // In other cases, subtract what we have
         * this.freeCPUs.set(free - request);
         * return request;
         * }
         */
    }

    /**
     * Releases a number of CPUSs previously allocated.<br/>
     * <br/>
     *
     * This function is only used internally. Also note that it is essential to call <code>releaseCPUs</code> after the
     * application stopped using them.
     *
     * @param toRelease The number of CPUs to release.
     */
    public void releaseCPUs(int toRelease) {
        // When looking at our benchmarks, it seems this does not speed up things, see Issue #12.
        /*
         * synchronized (this.freeCPUs) {
         * final int free = this.freeCPUs.get();
         * this.freeCPUs.set(Math.min(this.profileInformation.numCPUs, free + toRelease));
         * }
         */
    }
}
TOP

Related Classes of net.jcores.jre.CommonCore

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.