ReportConfiguration.java
/*
* Licensed to the Apache Software Foundation (ASF) under one *
* or more contributor license agreements. See the NOTICE file *
* distributed with this work for additional information *
* regarding copyright ownership. The ASF licenses this file *
* to you under the Apache License, Version 2.0 (the *
* "License"); you may not use this file except in compliance *
* with the License. You may obtain a copy of the License at *
* *
* http://www.apache.org/licenses/LICENSE-2.0 *
* *
* Unless required by applicable law or agreed to in writing, *
* software distributed under the License is distributed on an *
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
* KIND, either express or implied. See the License for the *
* specific language governing permissions and limitations *
* under the License. *
*/
package org.apache.rat;
import java.io.File;
import java.io.FileFilter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.SortedSet;
import java.util.function.Consumer;
import org.apache.commons.io.function.IOSupplier;
import org.apache.rat.analysis.IHeaderMatcher;
import org.apache.rat.commandline.StyleSheets;
import org.apache.rat.config.AddLicenseHeaders;
import org.apache.rat.config.exclusion.ExclusionProcessor;
import org.apache.rat.config.exclusion.StandardCollection;
import org.apache.rat.config.results.ClaimValidator;
import org.apache.rat.configuration.builders.AnyBuilder;
import org.apache.rat.document.DocumentName;
import org.apache.rat.document.DocumentNameMatcher;
import org.apache.rat.document.FileDocument;
import org.apache.rat.license.ILicense;
import org.apache.rat.license.ILicenseFamily;
import org.apache.rat.license.LicenseSetFactory;
import org.apache.rat.license.LicenseSetFactory.LicenseFilter;
import org.apache.rat.report.IReportable;
import org.apache.rat.utils.DefaultLog;
import org.apache.rat.utils.Log.Level;
import org.apache.rat.utils.ReportingSet;
import org.apache.rat.walker.FileListWalker;
import org.apache.rat.walker.IReportableListWalker;
/**
* A configuration object is used by the front end to invoke the
* {@link Reporter}. The sole purpose of the frontends is to create the
* configuration and invoke the {@link Reporter}.
*/
public class ReportConfiguration {
/**
* The styles of processing for various categories of documents.
*/
public enum Processing {
/** List file as present only */
NOTIFICATION("List file as present"),
/** List all present licenses */
PRESENCE("List any licenses found"),
/** List all present licenses and unknown licenses */
ABSENCE("List licenses found and any unknown licences");
/**
* Description of the processing
*/
private final String description;
Processing(final String description) {
this.description = description;
}
/**
* Gets the description of the processing type.
* @return the description of the processing type.
*/
public String desc() {
return description;
}
}
/** The LicenseSetFactory for the configuration */
private final LicenseSetFactory licenseSetFactory;
/**
* {@code true} if we are adding license headers to the files.
*/
private boolean addingLicenses;
/**
* {@code true} if we are adding license headers in place (no *.new files)
*/
private boolean addingLicensesForced;
/**
* The copyright message to add if we are adding headers. Will be null if we are not
* adding copyright messages.
*/
private String copyrightMessage;
/**
* The IOSupplier that provides the output stream to write the report to.
*/
private IOSupplier<OutputStream> out;
/**
* The IOSupplier that provides the stylesheet to style the XML output.
*/
private IOSupplier<InputStream> styleSheet;
/**
* A list of files to read file names from.
*/
private final List<File> sources;
/**
* A list of reportables to process;
*/
private final List<IReportable> reportables;
/**
* A predicate to test if a path should be included in the processing.
*/
private final ExclusionProcessor exclusionProcessor;
/**
* The default filter for displaying families.
*/
private LicenseFilter listFamilies;
/**
* The default filter for displaying licenses.
*/
private LicenseFilter listLicenses;
/**
* {@code true} if this is a dry run and no processing is to take place.
*/
private boolean dryRun;
/**
* How to process ARCHIVE document types.
*/
private Processing archiveProcessing;
/**
* How to process STANDARD document types.
*/
private Processing standardProcessing;
/**
* The ClaimValidator to validate min/max counts and similar claims.
*/
private final ClaimValidator claimValidator;
/**
* Constructor
*/
public ReportConfiguration() {
licenseSetFactory = new LicenseSetFactory();
listFamilies = Defaults.LIST_FAMILIES;
listLicenses = Defaults.LIST_LICENSES;
dryRun = false;
exclusionProcessor = new ExclusionProcessor();
claimValidator = new ClaimValidator();
sources = new ArrayList<>();
reportables = new ArrayList<>();
}
/**
* Report the excluded files to the appendable object.
* @param appendable the appendable object to write to.
*/
public void reportExclusions(final Appendable appendable) {
try {
exclusionProcessor.reportExclusions(appendable);
} catch (IOException e) {
DefaultLog.getInstance().warn("Unable to report exclusions", e);
}
}
/**
* Adds a file as a source of files to scan.
* The file must be a text file that lists files to be included.
* File within the file must be in linux format with a
* "/" file separator.
* @param file the file to process.
*/
public void addSource(final File file) {
notNull(file, "File may not be null.");
sources.add(file);
}
private void notNull(final Object o, final String msg) {
if (o == null) {
throw new ConfigurationException(msg);
}
}
/**
* Adds a Reportable as a source of files to scan.
* @param reportable the reportable to process.
*/
public void addSource(final IReportable reportable) {
notNull(reportable, "Reportable may not be null.");
reportables.add(reportable);
}
/**
* Returns {@code true} if the configuration has any sources defined.
* @return {@code true} if the configuration has any sources defined.
*/
public boolean hasSource() {
return !reportables.isEmpty() || !sources.isEmpty();
}
/**
* Gets a builder initialized with any files specified as sources.
* @return a configured builder.
*/
public IReportableListWalker.Builder getSources() {
DocumentName name = DocumentName.builder(new File(".")).build();
IReportableListWalker.Builder builder = IReportableListWalker.builder(name);
sources.forEach(file -> builder.addReportable(new FileListWalker(new FileDocument(file, DocumentNameMatcher.MATCHES_ALL))));
reportables.forEach(builder::addReportable);
return builder;
}
/**
* Gets the matcher that matches generated text.
* @return the matcher that matches generated text.
*/
public IHeaderMatcher getGeneratedMatcher() {
return new AnyBuilder().setResource("/org/apache/rat/generation-keywords.txt").build();
}
/**
* Retrieves the archive processing type.
* @return The archive processing type.
*/
public Processing getArchiveProcessing() {
return archiveProcessing == null ? Defaults.ARCHIVE_PROCESSING : archiveProcessing;
}
/**
* Sets the archive processing type. If not set will default to NOTIFICATION.
* @param archiveProcessing the type of processing archives should have.
*/
public void setArchiveProcessing(final Processing archiveProcessing) {
this.archiveProcessing = archiveProcessing;
}
/**
* Retrieves the archive processing type.
* @return The archive processing type.
*/
public Processing getStandardProcessing() {
return standardProcessing == null ? Defaults.STANDARD_PROCESSING : standardProcessing;
}
/**
* Sets the archive processing type. If not set will default to NOTIFICATION.
* @param standardProcessing the type of processing archives should have.
*/
public void setStandardProcessing(final Processing standardProcessing) {
this.standardProcessing = standardProcessing;
}
/**
* Set the log level for reporting collisions in the set of license families.
* <p>NOTE: should be set before licenses or license families are added.</p>
* @param level The log level to use.
*/
public void logFamilyCollisions(final Level level) {
licenseSetFactory.logFamilyCollisions(level);
}
/**
* Sets the reporting option for duplicate license families.
* @param state The ReportingSet.Option to use for reporting.
*/
public void familyDuplicateOption(final ReportingSet.Options state) {
licenseSetFactory.familyDuplicateOption(state);
}
/**
* Sets the log level for reporting license collisions.
* @param level The log level.
*/
public void logLicenseCollisions(final Level level) {
licenseSetFactory.logLicenseCollisions(level);
}
/**
* Sets the reporting option for duplicate licenses.
* @param state the ReportingSt.Option to use for reporting.
*/
public void licenseDuplicateOption(final ReportingSet.Options state) {
licenseSetFactory.licenseDuplicateOption(state);
}
/**
* Set the level of license families that should be output in the XML document.
* @param filter the license families to list.
*/
public void listFamilies(final LicenseFilter filter) {
listFamilies = filter;
}
/**
* Return the current filter that determines which families will be output in the XML document.
* @return the filter that defines the families to list.
*/
public LicenseFilter listFamilies() {
return listFamilies;
}
/**
* Set the level of licenses that should be output in the XML document.
* @param filter the licenses to list.
*/
public void listLicenses(final LicenseFilter filter) {
listLicenses = filter;
}
/**
* Gets the selected license filter.
* @return the filter to limit license display.
*/
public LicenseFilter listLicenses() {
return listLicenses;
}
/**
* Sets the dry run flag.
* @param state the state for the dry run flag.
*/
public void setDryRun(final boolean state) {
dryRun = state;
}
/**
* Returns the state of the dry run flag.
* @return the state of the dry run flag.
*/
public boolean isDryRun() {
return dryRun;
}
/**
* Excludes a StandardCollection of patterns.
* @param collection the StandardCollection to exclude.
* @see ExclusionProcessor#addExcludedCollection(StandardCollection)
*/
public void addExcludedCollection(final StandardCollection collection) {
exclusionProcessor.addExcludedCollection(collection);
}
/**
* Excludes the file processor defined in the StandardCollection.
* @param collection the StandardCollection to exclude.
* @see ExclusionProcessor#addFileProcessor(StandardCollection)
*/
public void addExcludedFileProcessor(final StandardCollection collection) {
exclusionProcessor.addFileProcessor(collection);
}
/**
* Excludes files that match a FileFilter.
* @param fileFilter the file filter to match.
*/
public void addExcludedFilter(final FileFilter fileFilter) {
exclusionProcessor.addExcludedMatcher(new DocumentNameMatcher(fileFilter));
}
/**
* Excludes files that match a DocumentNameMatcher.
* @param matcher the DocumentNameMatcher to match.
*/
public void addExcludedMatcher(final DocumentNameMatcher matcher) {
exclusionProcessor.addExcludedMatcher(matcher);
}
/**
* Excludes files that match the pattern.
*
* @param patterns the collection of patterns to exclude.
* @see ExclusionProcessor#addIncludedPatterns(Iterable)
*/
public void addExcludedPatterns(final Iterable<String> patterns) {
exclusionProcessor.addExcludedPatterns(patterns);
}
/**
* Adds the patterns from the standard collection as included patterns.
* @param collection the standard collection to include.
*/
public void addIncludedCollection(final StandardCollection collection) {
exclusionProcessor.addIncludedCollection(collection);
}
/**
* Adds the fileFilter to filter files that should be included, this overrides any
* exclusion of the same files.
* @param fileFilter the filter to identify files that should be included.
*/
public void addIncludedFilter(final FileFilter fileFilter) {
exclusionProcessor.addIncludedMatcher(new DocumentNameMatcher(fileFilter));
}
/**
* Add file patterns that are to be included. These patterns override any exclusion of
* the same files.
* @param patterns The iterable of Strings containing the patterns.
*/
public void addIncludedPatterns(final Iterable<String> patterns) {
exclusionProcessor.addIncludedPatterns(patterns);
}
/**
* Get the DocumentNameMatcher that excludes files found in the directory tree..
* @param baseDir the DocumentName for the base directory.
* @return the DocumentNameMatcher for the base directory.
*/
public DocumentNameMatcher getDocumentExcluder(final DocumentName baseDir) {
return exclusionProcessor.getNameMatcher(baseDir);
}
/**
* Gets the IOSupplier with the style sheet.
* @return the Supplier of the InputStream that is the XSLT style sheet to style
* the report with.
*/
public IOSupplier<InputStream> getStyleSheet() {
return styleSheet;
}
/**
* Sets the style sheet for custom processing. The IOSupplier may be called
* multiple times, so the input stream must be able to be opened and closed
* multiple times.
* @param styleSheet the XSLT style sheet to style the report with.
*/
public void setStyleSheet(final IOSupplier<InputStream> styleSheet) {
this.styleSheet = styleSheet;
}
/**
* Adds the licenses and approved licenses from the defaults object to the
* configuration. <em>Side effect:</em> if the report should be styled and no
* style sheet has been set the plain stylesheet from the defaults will be used.
* @param defaults The defaults to set.
*/
public void setFrom(final Defaults defaults) {
licenseSetFactory.add(defaults.getLicenseSetFactory());
if (getStyleSheet() == null) {
setStyleSheet(StyleSheets.PLAIN.getStyleSheet());
}
defaults.getStandardExclusion().forEach(this::addExcludedCollection);
}
/**
* Sets the style sheet.
* @param styleSheet the XSLT style sheet file to style the report with.
*/
public void setStyleSheet(final File styleSheet) {
Objects.requireNonNull(styleSheet, "styleSheet file should not be null");
setStyleSheet(styleSheet.toURI());
}
/**
* Sets the style sheet for custom processing. The stylesheet may be opened
* multiple times so the URI must be capable of being opened multiple times.
* @param styleSheet the URI of the XSLT style sheet to style the report with.
*/
public void setStyleSheet(final URI styleSheet) {
Objects.requireNonNull(styleSheet, "Stylesheet file must not be null");
try {
setStyleSheet(styleSheet.toURL());
} catch (MalformedURLException e) {
throw new ConfigurationException("Unable to process stylesheet", e);
}
}
/**
* Sets the style sheet for custom processing. The stylesheet may be opened
* multiple times so the URL must be capable of being opened multiple times.
* @param styleSheet the URL of the XSLT style sheet to style the report with.
*/
public void setStyleSheet(final URL styleSheet) {
Objects.requireNonNull(styleSheet, "Stylesheet file must not be null");
setStyleSheet(styleSheet::openStream);
}
/**
* Sets the supplier for the output stream. The supplier may be called multiple
* times to provide the stream. Suppliers should prepare streams that are
* appended to and that can be closed. If an {@code OutputStream} should not be
* closed consider wrapping it in a {@code NoCloseOutputStream}
* @param out The OutputStream supplier that provides the output stream to write
* the report to. A null value will use System.out.
* @see NoCloseOutputStream
*/
public void setOut(final IOSupplier<OutputStream> out) {
this.out = out;
}
/**
* Sets the OutputStream supplier to use the specified file. The file may be
* opened and closed several times. File is deleted first and then may be
* repeatedly opened in append mode.
* @see #setOut(IOSupplier)
* @param file The file to create the supplier with.
*/
public void setOut(final File file) {
Objects.requireNonNull(file, "output file should not be null");
if (file.exists()) {
try {
Files.delete(file.toPath());
} catch (IOException e) {
DefaultLog.getInstance().warn("Unable to delete file: " + file);
}
}
File parent = file.getParentFile();
if (!parent.mkdirs() && !parent.isDirectory()) {
DefaultLog.getInstance().warn("Unable to create directory: " + file.getParentFile());
}
setOut(() -> new FileOutputStream(file, true));
}
/**
* Returns the output stream supplier. If no stream has been set returns a
* supplier for System.out.
* @return The supplier of the output stream to write the report to.
*/
public IOSupplier<OutputStream> getOutput() {
return out == null ? () -> new NoCloseOutputStream(System.out) : out;
}
/**
* Gets a PrintWriter that wraps the output stream.
* @return A supplier for a PrintWriter that wraps the output stream.
* @see #getOutput()
*/
public IOSupplier<PrintWriter> getWriter() {
return () -> new PrintWriter(new OutputStreamWriter(getOutput().get(), StandardCharsets.UTF_8));
}
/**
* Adds a license to the list of licenses. Does not add the license to the list
* of approved licenses.
* @param license The license to add to the list of licenses.
*/
public void addLicense(final ILicense license) {
licenseSetFactory.addLicense(license);
}
/**
* Adds a license to the list of licenses. Does not add the license to the list
* of approved licenses.
* @param builder The license builder to build and add to the list of licenses.
* @return The ILicense implementation that was added.
*/
public ILicense addLicense(final ILicense.Builder builder) {
return licenseSetFactory.addLicense(builder);
}
/**
* Adds multiple licenses to the list of licenses. Does not add the licenses to
* the list of approved licenses.
* @param licenses The licenses to add.
*/
public void addLicenses(final Collection<ILicense> licenses) {
licenseSetFactory.addLicenses(licenses);
}
/**
* Adds a license family to the list of families. Does not add the family to the
* list of approved licenses.
* @param family The license family to add to the list of license families.
*/
public void addFamily(final ILicenseFamily family) {
licenseSetFactory.addFamily(family);
}
/**
* Adds a license family to the list of families. Does not add the family to the
* list of approved licenses.
* @param builder The licenseFamily.Builder to build and add to the list of
* licenses.
*/
public void addFamily(final ILicenseFamily.Builder builder) {
licenseSetFactory.addFamily(builder);
}
/**
* Adds multiple families to the list of license families. Does not add the
* licenses to the list of approved licenses.
* @param families The license families to add.
*/
public void addFamilies(final Collection<ILicenseFamily> families) {
families.forEach(this::addApprovedLicenseCategory);
}
/**
* Adds an ILicenseFamily to the list of approved licenses.
* @param approvedILicenseFamily the LicenseFamily to add.
*/
public void addApprovedLicenseCategory(final ILicenseFamily approvedILicenseFamily) {
addApprovedLicenseCategory(approvedILicenseFamily.getFamilyCategory());
}
/**
* Adds a license family category (id) to the list of approved licenses
* @param familyCategory the category to add.
*/
public void addApprovedLicenseCategory(final String familyCategory) {
licenseSetFactory.approveLicenseCategory(familyCategory);
}
/**
* Adds a collection of license family categories to the set of approved license
* names.
* @param approvedLicenseCategories set of approved license categories.
*/
public void addApprovedLicenseCategories(final Collection<String> approvedLicenseCategories) {
approvedLicenseCategories.forEach(this::addApprovedLicenseCategory);
}
/**
* Adds a license family category to the list of approved licenses. <em>Once a
* license has been removed from the approved list it cannot be re-added</em>
* @param familyCategory the category to add.
*/
public void removeApprovedLicenseCategory(final String familyCategory) {
licenseSetFactory.removeLicenseCategory(ILicenseFamily.makeCategory(familyCategory));
}
/**
* Removes a license family category from the list of approved licenses.
* <em>Once a license has been removed from the approved list it cannot be
* re-added</em>
* @param familyCategory the family category to remove.
*/
public void removeApprovedLicenseCategories(final Collection<String> familyCategory) {
familyCategory.forEach(this::removeApprovedLicenseCategory);
}
/**
* Gets the SortedSet of approved license categories. <em>Once a license has
* been removed from the approved list it cannot be re-added</em>
* @param filter The LicenseFilter to filter the categories by.
* @return the Sorted set of approved license categories.
*/
public SortedSet<String> getLicenseCategories(final LicenseFilter filter) {
return licenseSetFactory.getLicenseCategories(filter);
}
/**
* Gets the SortedSet of approved license categories. <em>Once a license has
* been removed from the approved list it cannot be re-added</em>
* @param filter The LicenseFilter to filter the licenses by.
* @return the Sorted set of approved license categories.
*/
public SortedSet<ILicense> getLicenses(final LicenseFilter filter) {
return licenseSetFactory.getLicenses(filter);
}
/**
* Gets the SortedSet of approved license categories. <em>Once a license has
* been removed from the approved list it cannot be re-added</em>
* @param filter The LicenseFilter to filter the licenses by.
* @return the Sorted set of approved license categories.
*/
public SortedSet<String> getLicenseIds(final LicenseFilter filter) {
return licenseSetFactory.getLicenseIds(filter);
}
/**
* Adds an ILicenseFamily to the list of approved licenses.
* @param approvedLicense the License to add.
*/
public void addApprovedLicenseId(final ILicense approvedLicense) {
addApprovedLicenseId(approvedLicense.getId());
}
/**
* Adds a license family category (id) to the list of approved licenses
* @param licenseId the license id to add.
*/
public void addApprovedLicenseId(final String licenseId) {
licenseSetFactory.approveLicenseId(licenseId);
}
/**
* Adds a collection of license family categories to the set of approved license
* names.
* @param approvedLicenseIds set of approved license IDs.
*/
public void addApprovedLicenseIds(final Collection<String> approvedLicenseIds) {
approvedLicenseIds.forEach(this::addApprovedLicenseId);
}
/**
* Adds a license family category to the list of approved licenses. <em>Once a
* license has been removed from the approved list it cannot be re-added</em>
* @param licenseId the license ID to add.
*/
public void removeApprovedLicenseId(final String licenseId) {
licenseSetFactory.removeLicenseId(licenseId);
}
/**
* Removes a license family category from the list of approved licenses.
* <em>Once a license has been removed from the approved list it cannot be
* re-added</em>
* @param licenseIds the license IDs to remove.
*/
public void removeApprovedLicenseIds(final Collection<String> licenseIds) {
licenseIds.forEach(this::removeApprovedLicenseId);
}
/**
* Returns the optional license copyright being added if RAT is adding headers.
* This value is ignored, if no license headers are added.
* @return the optional copyright message.
* @see #isAddingLicenses()
*/
public String getCopyrightMessage() {
return copyrightMessage;
}
/**
* Sets the optional copyright message used if RAT is adding license headers.
* This value is ignored, if no license headers are added.
* @param copyrightMessage message to set.
* @see #isAddingLicenses()
*/
public void setCopyrightMessage(final String copyrightMessage) {
this.copyrightMessage = copyrightMessage;
}
/**
* Gets the flag that determines if license headers are "forced" overwriting existing files.
* This value is ignored if RAT is not adding licenses.
* @return {@code true} if RAT is forcing the adding license headers.
* @see #isAddingLicenses()
*/
public boolean isAddingLicensesForced() {
return addingLicensesForced;
}
/**
* Gets the flag that determines if license headers should be added if missing.
* @return whether RAT should add missing license headers.
* @see #isAddingLicensesForced()
* @see #getCopyrightMessage()
*/
public boolean isAddingLicenses() {
return addingLicenses;
}
/**
* Sets whether RAT should enable, disable, or force the adding of license
* headers.
* @param addLicenseHeaders enables/disables or forces adding of licenses
* headers.
* @see #isAddingLicenses()
* @see #setCopyrightMessage(String)
*/
public void setAddLicenseHeaders(final AddLicenseHeaders addLicenseHeaders) {
addingLicenses = false;
addingLicensesForced = false;
switch (addLicenseHeaders) {
case FALSE:
// do nothing
break;
case FORCED:
addingLicensesForced = true;
addingLicenses = true;
break;
case TRUE:
addingLicenses = true;
break;
}
}
/**
* Gets a sorted set of ILicenseFamily objects based on {@code filter}. if
* filter is set:
* <ul>
* <li>{@code all} - All licenses families will be returned.</li>
* <li>{@code approved} - Only approved license families will be returned</li>
* <li>{@code none} - No license families will be returned</li>
* </ul>
* @param filter The license filter.
* @return The set of defined licenses.
*/
public SortedSet<ILicenseFamily> getLicenseFamilies(final LicenseFilter filter) {
return licenseSetFactory.getLicenseFamilies(filter);
}
/**
* Gets the ClaimValidator for the configuration.
* @return the ClaimValidator.
*/
public ClaimValidator getClaimValidator() {
return claimValidator;
}
/**
* Gets the enclosed LicenseSetFactory.
* @return the license set factory.
*/
public LicenseSetFactory getLicenseSetFactory() {
return licenseSetFactory;
}
/**
* Validates that the configuration is valid.
* @param logger String consumer to log warning messages to.
* @throws ConfigurationException on configuration error.
*/
public void validate(final Consumer<String> logger) {
if (!hasSource()) {
String msg = "At least one source must be specified";
logger.accept(msg);
throw new ConfigurationException(msg);
}
if (licenseSetFactory.getLicenses(LicenseFilter.ALL).isEmpty()) {
String msg = "You must specify at least one license";
logger.accept(msg);
throw new ConfigurationException(msg);
}
}
/**
* A wrapper around an output stream that does not close the output stream.
*/
public static class NoCloseOutputStream extends OutputStream {
/** the output stream this stream wraps */
private final OutputStream delegate;
/**
* Constructor.
* @param delegate the output stream to wrap.
*/
public NoCloseOutputStream(final OutputStream delegate) {
this.delegate = delegate;
}
@Override
public void write(final int arg0) throws IOException {
delegate.write(arg0);
}
/**
* Does not actually close the delegate. But does perform a flush.
* @throws IOException on Error.
*/
@Override
public void close() throws IOException {
this.delegate.flush();
}
@Override
public boolean equals(final Object obj) {
return delegate.equals(obj);
}
@Override
public void flush() throws IOException {
delegate.flush();
}
@Override
public int hashCode() {
return delegate.hashCode();
}
@Override
public String toString() {
return delegate.toString();
}
@Override
public void write(final byte[] arg0, final int arg1, final int arg2) throws IOException {
delegate.write(arg0, arg1, arg2);
}
@Override
public void write(final byte[] b) throws IOException {
delegate.write(b);
}
}
}