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

org.refcodes.serial.SectionComposite Maven / Gradle / Ivy

Go to download

Artifact providing generic (byte) serialization functionality including a TTY-/COM-Port implementation of the serial framework as well as a (local) loopback port.

The newest version!
// /////////////////////////////////////////////////////////////////////////////
// REFCODES.ORG
// /////////////////////////////////////////////////////////////////////////////
// This code is copyright (c) by Siegfried Steiner, Munich, Germany, distributed
// on an "AS IS" BASIS WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, and licen-
// sed under the following (see "http://en.wikipedia.org/wiki/Multi-licensing")
// licenses:
// -----------------------------------------------------------------------------
// GNU General Public License, v3.0 ("http://www.gnu.org/licenses/gpl-3.0.html")
// -----------------------------------------------------------------------------
// Apache License, v2.0 ("http://www.apache.org/licenses/TEXT-2.0")
// -----------------------------------------------------------------------------
// Please contact the copyright holding author(s) of the software artifacts in
// question for licensing issues not being covered by the above listed licenses,
// also regarding commercial licensing models or regarding the compatibility
// with other open source licenses.
// /////////////////////////////////////////////////////////////////////////////

package org.refcodes.serial;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.List;

import org.refcodes.factory.ClassTypeFactory;
import org.refcodes.factory.TypeFactory;
import org.refcodes.serial.Section.SectionMixin;

/**
 * A {@link SectionComposite} is a {@link Section} consisting of {@link Section}
 * elements of a variable length each: Each {@link Section} element in the
 * composite need not be of the same size. This is achieved by wrapping each
 * {@link Section} inside a dedicated {@link AllocSectionDecoratorSegment} being
 * a {@link Segment} providing the resulting {@link Section}'s length (with all
 * the composite's {@link Section} instances).
 * 
 * @param  The type of the {@link AllocSectionDecoratorSegment}
 *        describing the length of each {@link Section} element in the
 *        composite.
 * @param  The type of the {@link Section} elements to be contained in
 *        the {@link SectionComposite}.
 */
public class SectionComposite, CHILD extends Section> implements Section, SectionMixin, TransmissionComposite {

	// /////////////////////////////////////////////////////////////////////////
	// STATICS:
	// /////////////////////////////////////////////////////////////////////////

	private static final long serialVersionUID = 1L;

	// /////////////////////////////////////////////////////////////////////////
	// VARIABLES:
	// /////////////////////////////////////////////////////////////////////////

	private final TypeFactory _segmentFactory;
	private ALLOC[] _allocSegments;
	private final TypeFactory _allocSegmentFactory;

	// /////////////////////////////////////////////////////////////////////////
	// CONSTRUCTORS:
	// /////////////////////////////////////////////////////////////////////////

	/**
	 * Constructs a {@link SectionComposite} containing the provided
	 * {@link AllocSectionDecoratorSegment} elements and using the provided
	 * factories for creating {@link Segment} and {@link Section} instances.
	 * 
	 * @param aAllocSegmentFactory The {@link TypeFactory} creating
	 *        {@link Segment} instances.
	 * @param aSegmentFactory The {@link TypeFactory} creating {@link Section}
	 *        instances.
	 */
	@SuppressWarnings("unchecked")
	public SectionComposite( TypeFactory aAllocSegmentFactory, TypeFactory aSegmentFactory ) {
		_allocSegmentFactory = toAllocFactory( aAllocSegmentFactory, aSegmentFactory );
		_allocSegments = (ALLOC[]) Array.newInstance( aAllocSegmentFactory.getType(), 0 );
		_segmentFactory = aSegmentFactory;
	}

	/**
	 * Constructs a {@link SectionComposite} containing the provided
	 * {@link AllocSectionDecoratorSegment} elements and using the provided
	 * factories for creating {@link Segment} and {@link Section} instances.
	 * 
	 * @param aAllocSegmentFactory The {@link TypeFactory} creating
	 *        {@link Segment} instances.
	 * @param aSegmentFactory The {@link TypeFactory} creating {@link Section}
	 *        instances.
	 * @param aSegmentArray The {@link Section} elements being contained in this
	 *        instance.
	 */
	@SafeVarargs
	public SectionComposite( TypeFactory aAllocSegmentFactory, TypeFactory aSegmentFactory, CHILD... aSegmentArray ) {
		_allocSegmentFactory = toAllocFactory( aAllocSegmentFactory, aSegmentFactory );
		_allocSegments = toAllocArray( toAllocFactory( aAllocSegmentFactory, aSegmentFactory ), aSegmentArray );
		_segmentFactory = aSegmentFactory;
	}

	/**
	 * Constructs a {@link SectionComposite}. Instances for the {@link Segment}
	 * and {@link Section} elements are created using the provided {@link Class}
	 * instances.
	 * 
	 * @param aAllocSegmentClass The class from, which to produce the
	 *        {@link Segment} elements.
	 * @param aSegmentClass The class from, which to produce the {@link Section}
	 *        elements.
	 */
	@SuppressWarnings("unchecked")
	public SectionComposite( Class aAllocSegmentClass, Class aSegmentClass ) {
		_allocSegmentFactory = toAllocFactory( aAllocSegmentClass, aSegmentClass );
		_allocSegments = (ALLOC[]) Array.newInstance( aAllocSegmentClass, 0 );
		_segmentFactory = new ClassTypeFactory<>( aSegmentClass );
	}

	/**
	 * Constructs a {@link SectionComposite} containing the provided
	 * {@link AllocSectionDecoratorSegment} elements. Instances for the
	 * {@link Segment} and {@link Section} elements are created using the
	 * provided {@link Class} instances.
	 * 
	 * @param aAllocSegmentClass The class from, which to produce the
	 *        {@link Segment} elements.
	 * @param aSegmentClass The class from, which to produce the {@link Section}
	 *        elements.
	 * @param aSegmentArray The {@link Section} elements being contained in this
	 *        instance.
	 */
	@SafeVarargs
	public SectionComposite( Class aAllocSegmentClass, Class aSegmentClass, CHILD... aSegmentArray ) {
		_allocSegmentFactory = toAllocFactory( aAllocSegmentClass, aSegmentClass );
		_allocSegments = toAllocArray( new ClassTypeFactory<>( aAllocSegmentClass ), aSegmentArray );
		_segmentFactory = new ClassTypeFactory<>( aSegmentClass );
	}

	// /////////////////////////////////////////////////////////////////////////
	// METHODS:
	// /////////////////////////////////////////////////////////////////////////

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Sequence toSequence() {
		final Sequence theSequence = new ByteArraySequence();
		if ( _allocSegments != null ) {
			for ( ALLOC _allocSegment : _allocSegments ) {
				theSequence.append( _allocSegment.toSequence() );
			}
		}
		return theSequence;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void reset() {
		if ( _allocSegments != null && _allocSegments.length != 0 ) {
			for ( var eSegments : _allocSegments ) {
				eSegments.reset();
			}
		}
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public SerialSchema toSchema() {
		SerialSchema[] theSchemas = null;
		if ( _allocSegments != null && _allocSegments.length != 0 ) {
			theSchemas = new SerialSchema[_allocSegments.length];
			for ( int i = 0; i < theSchemas.length; i++ ) {
				theSchemas[i] = _allocSegments[i].toSchema();
			}
		}
		return new SerialSchema( getClass(), toSequence(), getLength(), "An array segment containing a variable length elements array as payload.", theSchemas );
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public int getLength() {
		int theLength = 0;
		if ( _allocSegments != null ) {
			for ( ALLOC _allocSegment : _allocSegments ) {
				theLength += _allocSegment.getLength();
			}
		}
		return theLength;
	}

	/**
	 * {@inheritDoc}
	 */
	@SuppressWarnings("unchecked")
	@Override
	public CHILD[] getChildren() {
		final CHILD[] theSegments = (CHILD[]) Array.newInstance( _segmentFactory.getType(), _allocSegments.length );
		for ( int i = 0; i < theSegments.length; i++ ) {
			theSegments[i] = _allocSegments[i].getDecoratee();
		}
		return theSegments;
	}

	/**
	 * {@inheritDoc}
	 */
	@SuppressWarnings("unchecked")
	@Override
	public void fromTransmission( Sequence aSequence, int aOffset, int aLength ) throws TransmissionException {
		int eOffset = aOffset;
		final List theAllocSegments = new ArrayList<>();
		ALLOC eAllocSegment;
		while ( aOffset + aLength > eOffset ) {
			eAllocSegment = _allocSegmentFactory.create();
			eOffset = eAllocSegment.fromTransmission( aSequence, eOffset );
			theAllocSegments.add( eAllocSegment );
		}
		_allocSegments = theAllocSegments.toArray( (ALLOC[]) Array.newInstance( _allocSegments.getClass().getComponentType(), theAllocSegments.size() ) );
	}

	/**
	 * {@inheritDoc}
	 */
	@SuppressWarnings("unchecked")
	@Override
	public void receiveFrom( InputStream aInputStream, int aLength, OutputStream aReturnStream ) throws IOException {
		final List theAllocSegments = new ArrayList<>();
		ALLOC eAllocSegment;
		int theLength = 0;
		while ( aLength > theLength ) {
			eAllocSegment = _allocSegmentFactory.create();
			eAllocSegment.receiveFrom( aInputStream, aReturnStream );
			theLength += eAllocSegment.getLength();
			theAllocSegments.add( eAllocSegment );
		}
		_allocSegments = theAllocSegments.toArray( (ALLOC[]) Array.newInstance( _allocSegments.getClass().getComponentType(), theAllocSegments.size() ) );
	}

	// /////////////////////////////////////////////////////////////////////////
	// HOOKS:
	// /////////////////////////////////////////////////////////////////////////

	/**
	 * Hook for easily setting the children.
	 * 
	 * @param aChildren The children to be set.
	 */
	protected void setChildren( CHILD[] aChildren ) {
		_allocSegments = toAllocArray( toAllocFactory( _allocSegmentFactory, _segmentFactory ), aChildren );
	}

	// /////////////////////////////////////////////////////////////////////////
	// HELPER:
	// /////////////////////////////////////////////////////////////////////////

	@SuppressWarnings("unchecked")
	private static , SEGMENT extends Section> ALLOC[] toAllocArray( TypeFactory aAllocFactory, SEGMENT[] aSegmentArray ) {
		final AllocSectionDecoratorSegment[] theAllocSegments = new AllocSectionDecoratorSegment[aSegmentArray.length];
		for ( int i = 0; i < theAllocSegments.length; i++ ) {
			theAllocSegments[i] = aAllocFactory.create();
			theAllocSegments[i].setDecoratee( aSegmentArray[i] );
		}
		return (ALLOC[]) theAllocSegments;
	}

	private static , SEGMENT extends Section> TypeFactory toAllocFactory( TypeFactory aAllocSegmentFactory, TypeFactory aSegmentFactory ) {
		return new TypeFactory() {

			private Class _type = null;

			@SuppressWarnings("unchecked")
			@Override
			public ALLOC create() {
				final ALLOC theAllocSegment = aAllocSegmentFactory.create();
				if ( _type == null ) {
					_type = (Class) theAllocSegment.getClass();
				}
				theAllocSegment.setDecoratee( aSegmentFactory.create() );
				return theAllocSegment;
			}

			@SuppressWarnings("unchecked")
			@Override
			public Class getType() {
				if ( _type == null ) {
					synchronized ( this ) {
						if ( _type == null ) {
							_type = (Class) create().getClass();
						}
					}
				}
				return _type;
			}
		};
	}

	private static , SEGMENT extends Section> TypeFactory toAllocFactory( Class aAllocSegmentClass, Class aSegmentClass ) {
		return new TypeFactory() {

			TypeFactory _allocSegmentFactory = new ClassTypeFactory<>( aAllocSegmentClass );
			TypeFactory _segmentSegmentFactory = new ClassTypeFactory<>( aSegmentClass );

			@Override
			public ALLOC create() {
				final ALLOC theAllocSegment = _allocSegmentFactory.create();
				theAllocSegment.setDecoratee( _segmentSegmentFactory.create() );
				return theAllocSegment;
			}

			@Override
			public Class getType() {
				return aAllocSegmentClass;
			}
		};
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy