All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.algart.contexts.SubContext Maven / Gradle / Ivy

Go to download

Open-source Java libraries, supporting generalized smart arrays and matrices with elements of any types, including a wide set of 2D-, 3D- and multidimensional image processing and other algorithms, working with arrays and matrices.

There is a newer version: 1.4.23
Show newest version
/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2007-2024 Daniel Alievsky, AlgART Laboratory (http://algart.net)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

package net.algart.contexts;

import java.util.HashSet;
import java.util.Arrays;
import java.util.Objects;

import net.algart.arrays.MemoryModel;
import net.algart.arrays.SimpleMemoryModel;

/**
 * 

A tool allowing to build a new context, called "sub-context", * that inherits behavior of an existing context with some changes or extensions.

* *

There are two basic ways to create a sub-context.

* *

The first way is inheriting this class with using the protected constructor * {@link #SubContext(Context) SubContext(Context superContext)}. * New subclass cannot override {@link #as(Class)} and {@link #is(Class)} * methods, but may (and should) implement some additional specific context interfaces * (for example, {@link ProgressUpdater}, {@link ArrayMemoryContext} or your custom contexts). * The {@link #as(Class)} and {@link #is(Class)} method of the created sub-context * will just call these methods of the super-context, excepting the case * when the required contextClass is an interface implemented by your sub-context class. * In the last case, {@link #as(Class)} method will return the reference to your sub-context instance * and {@link #is(Class)} will return true. * This technique is useful when you need to extend or override some * functionality of the given context.

* *

The second way of creating sub-context is using the public constructor * {@link #SubContext(Context, Class[]) SubContext(Context superContext, Class ...allowedClasses)}, * maybe, together with inheritance as in the first way. * In this case, {@link #as(Class)} and {@link #is(Class)} will also pass the request * to the super-context, as described above, if the required contextClass * is implemented by your sub-context class (in particular, if you do not extend * this class and just call the public constructor). * However, the contextClass will be checked, is it in the classes list * passed to the constructor. If contextClass is not in this list * (and is not implemented by your sub-context), it is considered as unallowed, * and the request is declined: {@link #as(Class)} throws an exception, * and {@link #is(Class)} method returns false. * This technique allows to restrict a set of passed contexts * by only well-known, safe contexts.

* *

Another constructors may provide another behavior: please see comments to that constructors.

* * @author Daniel Alievsky */ public class SubContext extends AbstractContext implements Context { private final Context superContext; private final HashSet> allowedClassesSet; private final MemoryModel memoryModel; /** * Creates new context on the base of the passed super-context. * * @param superContext super-context. */ protected SubContext(Context superContext) { super(false); // the constructor argument does not matter: we override both as and is methods Objects.requireNonNull(superContext, "Null superContext argument"); this.superContext = superContext; this.allowedClassesSet = null; this.memoryModel = null; } /** * Creates new context on the base of the passed super-context * with the restricted set of allowed context classes. * * @param superContext super-context. * @param allowedClasses the set of served specific contexts * (in addition to interfaces implemented by this instance). * @throws NullPointerException if superContext or one of allowedClasses is {@code null}. * @throws IllegalArgumentException if one of allowedClasses is not a {@link Context}. */ public SubContext(Context superContext, Class ...allowedClasses) { super(false); // the constructor argument does not matter: we override both as and is methods Objects.requireNonNull(superContext, "Null superContext argument"); for (int k = 0; k < allowedClasses.length; k++) { Class c = allowedClasses[k]; Objects.requireNonNull(c, "Null allowedClasses[" + k + "] argument"); if (!Context.class.isAssignableFrom(c)) { throw new IllegalArgumentException("allowedClasses[" + k + "] does not inherit Context (" + c + ")"); } } this.superContext = superContext; this.allowedClassesSet = new HashSet>(Arrays.asList(allowedClasses)); this.memoryModel = null; } /** * Creates new context alike the {@link #SubContext(Context) base constructor} * with the only difference that {@link #as(Class) as(ArrayMemoryContext.class)} * method will return a {@link ArrayMemoryContext} describing the passed memory model. * See comments to {@link #as(Class)} and {@link #is(Class)} * method for more details. * * @param superContext super-context. * @param memoryModel desired memory model. * @throws NullPointerException if one of the arguments is {@code null}. */ public SubContext(Context superContext, MemoryModel memoryModel) { super(false); // the constructor argument does not matter: we override both as and is methods Objects.requireNonNull(superContext, "Null superContext argument"); Objects.requireNonNull(memoryModel, "Null memoryModel argument"); this.superContext = superContext; this.allowedClassesSet = null; this.memoryModel = memoryModel; } /** * This implementation returns the reference to this instance, if * contextClass.isAssignableFrom(thisInstance.getClass()), * or calls superContext.{@link #as(Class) as}(contextClass) * in another case. * *

If this instance was created by the constructor with the specified set of allowed classes * ({@link #SubContext(Context, Class[])}), * and the condition contextClass.isAssignableFrom(thisInstance.getClass()) is not fulfilled, * then context class is checked before passing to the superContext.{@link #as(Class) as} method. * Namely, if this class is not in the list of allowed contexts, passed to the constructor, * this method throws {@link UnsupportedContextException}. * *

If this instance was created by the constructor with the specified memory model * ({@link #SubContext(Context, MemoryModel)}), and if contextClass==ArrayMemoryContext.class, but * !contextClass.isAssignableFrom(thisInstance.getClass()), * then this method does not call superContext, but creates new implementation * of {@link ArrayMemoryContext} with {@link ArrayMemoryContext#getMemoryModel() getMemoryModel()}, * {@link ArrayMemoryContext#getMemoryModel(Class) getMemoryModel(Class)} and * {@link ArrayMemoryContext#getMemoryModel(String) getMemoryModel(String)} methods, * returning the memory model specified in the constructor. * The second {@link ArrayMemoryContext#getMemoryModel(Class) getMemoryModel(Class)} method * will return {@link SimpleMemoryModel#getInstance()}, if the required element type * is not supported by the memory model specified in the constructor. * * @param contextClass the class of returned object (or superclass, or implemented interface). * @return this instance. * @throws NullPointerException if contextClass is {@code null}. * @throws IllegalArgumentException if contextClass does not extends or implements * {@link Context} interface. * @throws UnsupportedContextException if this instance does not implement or extend the required type. */ public final T as(Class contextClass) { Objects.requireNonNull(contextClass, "Null contextClass argument"); if (!Context.class.isAssignableFrom(contextClass)) { throw new IllegalArgumentException("The contextClass argument is not a context class (" + contextClass.getName() + ")"); } if (contextClass.isAssignableFrom(getClass())) { return contextClass.cast(this); } else { if (allowedClassesSet != null && !allowedClassesSet.contains(contextClass)) { throw new UnsupportedContextException("Unallowed context class: " + contextClass.getName()); } if (contextClass == ArrayMemoryContext.class && this.memoryModel != null) { return contextClass.cast(new MemorySubContext()); } return superContext.as(contextClass); } } /** * This implementation returns true if contextClass is not {@code null} * and contextClass.isAssignableFrom(thisInstance.getClass()). * In another case, if this instance was created by the constructor with the specified set of allowed classes * ({@link #SubContext(Context, Class[])}) and if the passed context class is not * in the list of allowed contexts, passed to the constructor, * this implementation returns false. * *

If this instance was created by the constructor with the specified memory model * ({@link #SubContext(Context, MemoryModel)}), * and if contextClass==ArrayMemoryContext.class, * this implementation returns true. * *

In all other cases, this implementation returns * superContext.{@link #is is}(contextClass). * * @param contextClass the class or interface of a sub-context. * @return true if this context class can be processed by {@link #as(Class)} method. */ public final boolean is(Class contextClass) { if (contextClass == null || !Context.class.isAssignableFrom(contextClass)) { return false; } if (contextClass.isAssignableFrom(getClass())) { return true; } if (allowedClassesSet != null && !allowedClassesSet.contains(contextClass)) { return false; } if (contextClass == ArrayMemoryContext.class && this.memoryModel != null) { return true; } return superContext.is(contextClass); } private class MemorySubContext extends AbstractContext implements ArrayMemoryContext { private MemorySubContext() { super(false); } public MemoryModel getMemoryModel() { return memoryModel; } public MemoryModel getMemoryModel(Class elementType) { return memoryModel.isElementTypeSupported(elementType) ? memoryModel : SimpleMemoryModel.getInstance(); } public MemoryModel getMemoryModel(String settings) { Objects.requireNonNull(settings, "Null settings argument"); return memoryModel; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy