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

org.refcodes.serial.FileSection 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.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.util.function.Supplier;

import org.refcodes.textual.CaseStyleBuilder;

/**
 * A {@link FileSection} represents a {@link File} on the file system and can be
 * used to receive or to transmit a {@link File}. Using a {@link Supplier}, one
 * can use for example a {@link StringSection}'s value (as of
 * {@link StringSection#getPayload()}) to determine the underlying {@link File}
 * name dynamically. Whenever the underlying {@link File} is to be accessed,
 * then the {@link Supplier} is called (if provided) to construct the according
 * File dynamically. This way, a file name provided by a {@link StringSection}
 * can be used for the {@link FileSection} within the same transmission.
 */
public class FileSection extends AbstractPayloadSection {

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

	private static final long serialVersionUID = 1L;

	// /////////////////////////////////////////////////////////////////////////
	// CONSTANTS:
	// /////////////////////////////////////////////////////////////////////////

	private static final int WRITE_BLOCK_FILE_SIZE = 4096;

	public static final String FILE_PATH = "FILE_PATH";
	public static final String FILE_SIZE = "FILE_SIZE";
	public static final String FILE_EXISTS = "FILE_EXISTS";
	public static final String FILE = "FILE";

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

	private Supplier _filePathSupplier = null;

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

	/**
	 * Constructs a {@link FileSection}.
	 * 
	 * @param aAlias The {@link FileSection}'S alias.
	 * @param aFile The {@link File} representing the {@link FileSection}.
	 */
	public FileSection( String aAlias, File aFile ) {
		super( aAlias, aFile );
	}

	/**
	 * Constructs a {@link FileSection}.
	 * 
	 * @param aFile The {@link File} representing the {@link FileSection}.
	 */
	public FileSection( File aFile ) {
		super( CaseStyleBuilder.asKebabCase( FileSection.class.getSimpleName() ), aFile );
	}

	/**
	 * Constructs a {@link FileSection}.
	 * 
	 * @param aAlias The {@link FileSection}'S alias.
	 * @param aFilePath The file path of {@link File} representing the
	 *        {@link FileSection}.
	 */
	public FileSection( String aAlias, String aFilePath ) {
		super( aAlias, new File( aFilePath ) );
	}

	/**
	 * Constructs a {@link FileSection}.
	 * 
	 * @param aFilePath The file path of {@link File} representing the
	 *        {@link FileSection}.
	 */
	public FileSection( String aFilePath ) {
		super( CaseStyleBuilder.asKebabCase( FileSection.class.getSimpleName() ), new File( aFilePath ) );
	}

	/**
	 * Constructs a {@link FileSection}, the underlying {@link File} is created
	 * on demand dynamically using the provided {@link Supplier}.
	 * 
	 * @param aFilePathSupplier The {@link Supplier} of the file path of
	 *        {@link File} representing the {@link FileSection}. Whenever the
	 *        underlying file is to be accessed, then the {@link Supplier} is
	 *        called to construct the according {@link File}.
	 */
	public FileSection( Supplier aFilePathSupplier ) {
		super( CaseStyleBuilder.asKebabCase( FileSection.class.getSimpleName() ), null );
		_filePathSupplier = aFilePathSupplier;
	}

	/**
	 * Constructs a {@link FileSection}, the underlying {@link File} is created
	 * on demand dynamically using the provided {@link Supplier}.
	 * 
	 * @param aAlias The {@link FileSection}'S alias.
	 * @param aBasePath The base path for the path provided by the
	 *        {@link Supplier}.
	 * @param aFilePathSupplier The {@link Supplier} of the file path of
	 *        {@link File} representing the {@link FileSection}. Whenever the
	 *        underlying file is to be accessed, then the {@link Supplier} is
	 *        called to construct the according {@link File}.
	 */
	public FileSection( String aAlias, String aBasePath, Supplier aFilePathSupplier ) {
		super( aAlias, new File( aBasePath ) );
		_filePathSupplier = aFilePathSupplier;
	}

	/**
	 * Constructs a {@link FileSection}, the underlying {@link File} is created
	 * on demand dynamically using the provided {@link Supplier}.
	 * 
	 * @param aBasePath The base path for the path provided by the
	 *        {@link Supplier}.
	 * @param aFilePathSupplier The {@link Supplier} of the file path of
	 *        {@link File} representing the {@link FileSection}. Whenever the
	 *        underlying file is to be accessed, then the {@link Supplier} is
	 *        called to construct the according {@link File}.
	 */
	public FileSection( String aBasePath, Supplier aFilePathSupplier ) {
		super( CaseStyleBuilder.asKebabCase( FileSection.class.getSimpleName() ), new File( aBasePath ) );
		_filePathSupplier = aFilePathSupplier;
	}

	/**
	 * Constructs a {@link FileSection}, the underlying {@link File} is created
	 * on demand dynamically using the provided {@link Supplier}.
	 * 
	 * @param aAlias The {@link FileSection}'S alias.
	 * @param aBasePath The {@link File} representing the base path for the path
	 *        provided by the {@link Supplier}.
	 * @param aFilePathSupplier The {@link Supplier} of the file path of
	 *        {@link File} representing the {@link FileSection}. Whenever the
	 *        underlying file is to be accessed, then the {@link Supplier} is
	 *        called to construct the according {@link File}.
	 */
	public FileSection( String aAlias, File aBasePath, Supplier aFilePathSupplier ) {
		super( aAlias, aBasePath );
		_filePathSupplier = aFilePathSupplier;
	}

	/**
	 * Constructs a {@link FileSection}, the underlying {@link File} is created
	 * on demand dynamically using the provided {@link Supplier}.
	 * 
	 * @param aBasePath The {@link File} representing the base path for the path
	 *        provided by the {@link Supplier}.
	 * @param aFilePathSupplier The {@link Supplier} of the file path of
	 *        {@link File} representing the {@link FileSection}. Whenever the
	 *        underlying file is to be accessed, then the {@link Supplier} is
	 *        called to construct the according {@link File}.
	 */
	public FileSection( File aBasePath, Supplier aFilePathSupplier ) {
		super( CaseStyleBuilder.asKebabCase( FileSection.class.getSimpleName() ), aBasePath );
		_filePathSupplier = aFilePathSupplier;
	}

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

	/**
	 * {@inheritDoc}
	 */
	@Override
	public SerialSchema toSchema() {
		final File theFile = toPayloadFile();
		final SerialSchema theSchema = new SerialSchema( getAlias(), getClass(), "A file segment containing a payload referenced by a file.", getLength() );
		theSchema.put( FILE_PATH, theFile.getAbsolutePath() );
		theSchema.put( FILE_SIZE, theFile.length() );
		theSchema.put( FILE_EXISTS, theFile.exists() );
		theSchema.put( FILE, theFile.isFile() );
		return theSchema;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void fromTransmission( Sequence aSequence, int aOffset, int aLength ) throws TransmissionException {
		final File theFile = toPayloadFile();
		final byte[] theByte = new byte[1];
		try ( FileOutputStream theOut = new FileOutputStream( theFile ); ) {
			for ( int i = 0; i < aLength; i++ ) {
				theByte[0] = aSequence.getByteAt( i + aOffset );
				theOut.write( theByte );
			}
		}
		catch ( ArrayIndexOutOfBoundsException | IOException e ) {
			throw new TransmissionException( "Cannot send transmission for sequence <" + aSequence.toHexString() + "> at offset <" + aOffset + "> with length <" + aLength + ">!", e );
		}
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void receiveFrom( InputStream aInputStream, int aLength, OutputStream aReturnStream ) throws IOException {
		final File theFile = toPayloadFile();
		try ( OutputStream theOut = new BufferedOutputStream( new FileOutputStream( theFile ) ) ) {
			//	RetryTimeout theTimeout = new RetryTimeout( IoPollLoopTime.MIN.getTimeInMs(), IoRetryCount.MIN.getValue() );
			//	while ( aInputStream.available() == 0 && theTimeout.nextRetry() ) {}
			//	theTimeout.restart();
			//	for ( int i = 0; i < aLength; i++ ) {
			//		theOut.write( aInputStream.read() );
			//	}

			int count = 0;
			int size;
			final byte[] theBuffer = new byte[WRITE_BLOCK_FILE_SIZE];
			while ( aLength - count >= theBuffer.length ) {
				size = aInputStream.read( theBuffer );
				count += size;
				theOut.write( theBuffer, 0, size );
				theOut.flush();
			}
			while ( aLength > count ) {
				size = aInputStream.read( theBuffer, 0, aLength - count );
				count += size;
				theOut.write( theBuffer, 0, size );
				theOut.flush();
			}
		}
		catch ( ArrayIndexOutOfBoundsException e ) {
			throw new TransmissionException( "Cannot receive transmission from input stream <" + aInputStream + "> and return stream <" + aReturnStream + "> with length <" + aLength + ">!", e );
		}
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public int getLength() {
		return (int) toPayloadFile().length();
	}

	/**
	 * {@inheritDoc} ATTENTION: Use this method with care as all of the
	 * {@link File}'s content is loaded into the {@link Sequence} (and therewith
	 * into memory) as a byte array!
	 */
	@Override
	public Sequence toSequence() {
		Sequence theSequence;
		final File theFile = toPayloadFile();
		try ( FileInputStream theIn = new FileInputStream( theFile ) ) {
			final byte[] theFileBytes = new byte[(int) theFile.length()];
			theIn.read( theFileBytes );
			theSequence = new ByteArraySequence( theFileBytes );
		}
		catch ( IOException ignoree ) {
			theSequence = new ByteArraySequence();
		}
		return theSequence;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void transmitTo( OutputStream aOutputStream, InputStream aReturnStream ) throws IOException {
		final File theFile = toPayloadFile();
		Files.copy( theFile.toPath(), aOutputStream );
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public PayloadTransmission withPayload( File aPayload ) {
		setPayload( aPayload );
		return this;
	}

	/**
	 * Determines whether we have a "dynamic" {@link File} as of a
	 * {@link Supplier} being or a "static" {@link File} (or a file path).
	 * 
	 * @return The according {@link File}.
	 */
	public File toPayloadFile() {
		if ( _filePathSupplier != null ) {
			if ( _payload != null ) {
				return new File( _payload, _filePathSupplier.get() );
			}
			return new File( _filePathSupplier.get() );
		}
		return _payload;
	}

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

	// private String toNormalizedFileName( String aFileName ) {
	//	while ( aFileName.startsWith( File.pathSeparator ) ) {
	//		aFileName = aFileName.substring( aFileName.length() );
	//	}
	//	while ( aFileName.endsWith( File.pathSeparator ) ) {
	//		aFileName = aFileName.substring( 0, aFileName.length() - File.pathSeparator.length() );
	//	}
	//	return aFileName;
	// }
	//
	// private String toNormalizedPath( String aPath ) {
	//	while ( aPath.endsWith( File.pathSeparator ) ) {
	//		aPath = aPath.substring( 0, aPath.length() - File.pathSeparator.length() );
	//	}
	//	return aPath;
	// }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy