
org.refcodes.serial.FileSection Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of refcodes-serial Show documentation
Show all versions of refcodes-serial Show documentation
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