Container.java
// <editor-fold defaultstate="collapsed" desc="license">
/*
* Copyright (c) 2014, Karl H. Beckers
* 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 <ORGANIZATION> 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 HOLDER 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.
**/
// </editor-fold>
package net.jarre_de_the.griffin.types.data;
import java.util.List;
import net.jarre_de_the.griffin.exception.NoFieldFoundException;
import net.jarre_de_the.griffin.types.field.AbstractField;
/**
* Interface for all data types which can contain fields.
*
* @author charly4711
*/
public interface Container {
/**
* Searches fields contained in this Container. This search recurses down
* into nested Containers.
*
* @param <T>
* @Container} for a field of the give name (label) and/or field type. This
* method recurses down other {
* @Container} objects contained in this one. Either parameter can be null
* to always match. The method must not return null but an empty list, if no
* match was found.
*
* @param clazz Class of field type to look for or null for any.
* @param label Name of the field to find or null for any.
* @return The list of (potentially multiple) fields found wrapped in
* {@FoundField} objects that also contain the path to the field from
* the Container that was searched on.
*/
<T extends AbstractField> List<FoundField<T>> findField(Class<T> clazz,
byte[] label);
/**
* Behaves like @see #findField(Class<T>, byte[]) except that it also
* compares the values of the fields to the value specified. Only an exact
* match will count as a match.
*
* @param <T>
* @param <M>
* @param clazz
* @param label
* @param value
* @return
*/
<T extends AbstractField, M extends AbstractData> List<FoundField<T>>
findField(Class<T> clazz, byte[] label, M value);
/**
* Behaves like @see #findField(Class<T>, byte[]) except that it also
* uses toString() on the values of the fields and matches them to the
* specifiec regular expression.
*
* @param <T>
* @param clazz
* @param label
* @param regex
* @return
*/
<T extends AbstractField> List<FoundField<T>>
findField(Class<T> clazz, byte[] label, String regex);
/**
* Searches fields contained directly in this {@Container} for a field
* of the give label and field type. This method will not recurse and
* therefore just find a single field.
*
* @param <T>
* @throws NoFieldFoundException if no match was found.
* @param clazz Class of field type to look for or null for any.
* @param label Name of the field to find. Passing in null here is a sure
* way of getting a NoFieldFoundException.
* @return The hopefully unique field found.
*/
<T extends AbstractField> T findLocalField(Class<T> clazz, byte[] label);
/**
* Searches a field by an absolutely specified position in the tree.
*
* @throws NoFieldFoundException if the path doesn't identify an existing
* field.
* @param path Array of integer positions at each level below the container.
* @return The field found.
*/
AbstractField findFieldByPath(int[] path);
/**
* Wrapper for results of Container.findField() methods.
*
* @param <T>
*/
public static class FoundField<T extends AbstractField> {
private final T field;
private final int[] path;
public FoundField(T field, int[] path) {
this.field = field;
if (null != path) {
this.path = new int[path.length];
System.arraycopy(path, 0, this.path, 0, path.length);
} else {
this.path = null;
}
}
public T getField() {
return field;
}
public int[] getPath() {
int[] result;
if (null != path) {
result = new int[path.length];
System.arraycopy(path, 0, result, 0, path.length);
} else {
result = null;
}
return result;
}
}
}