001/*
002 * ============================================================================
003 *  Copyright © 2002-2021 by Thomas Thrien.
004 *  All Rights Reserved.
005 * ============================================================================
006 *  Licensed to the public under the agreements of the GNU Lesser General Public
007 *  License, version 3.0 (the "License"). You may obtain a copy of the License at
008 *
009 *       http://www.gnu.org/licenses/lgpl.html
010 *
011 *  Unless required by applicable law or agreed to in writing, software
012 *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
013 *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
014 *  License for the specific language governing permissions and limitations
015 *  under the License.
016 */
017
018package org.tquadrat.foundation.config.spi.prefs;
019
020import static org.apiguardian.api.API.Status.STABLE;
021import static org.tquadrat.foundation.lang.Objects.isNull;
022import static org.tquadrat.foundation.lang.Objects.requireNonNullArgument;
023
024import java.util.prefs.BackingStoreException;
025import java.util.prefs.Preferences;
026
027import org.apiguardian.api.API;
028import org.tquadrat.foundation.annotation.ClassVersion;
029import org.tquadrat.foundation.config.spi.InvalidPreferenceValueException;
030import org.tquadrat.foundation.function.Getter;
031import org.tquadrat.foundation.function.Setter;
032
033/**
034 *  <p>{@summary The abstract base class for an implementation of
035 *  {@link PreferenceAccessor}
036 *  for bulk data.}</p>
037 *  <p>The method
038 *  {@link Preferences#put(String, String) Preferences.put()}
039 *  limits the length for a value String to
040 *  {@value Preferences#MAX_VALUE_LENGTH}. If more data should be stored, the
041 *  method
042 *  {@link Preferences#putByteArray(String, byte[]) Preferences.putByteArray()}
043 *  can be used.</p>
044 *
045 *  @param  <T> The type of the property.
046 *
047 *  @extauthor Thomas Thrien - thomas.thrien@tquadrat.org
048 *  @version $Id: BulkDataAccessorBase.java 942 2021-12-20 02:04:04Z tquadrat $
049 *  @since 0.0.1
050 *
051 *  @UMLGraph.link
052 */
053@ClassVersion( sourceVersion = "$Id: BulkDataAccessorBase.java 942 2021-12-20 02:04:04Z tquadrat $" )
054@API( status = STABLE, since = "0.0.1" )
055public abstract class BulkDataAccessorBase<T> extends PreferenceAccessor<T>
056{
057        /*--------------*\
058    ====** Constructors **=====================================================
059        \*--------------*/
060    /**
061     *  Creates a new {@code BulkDataAccessorBase} instance.
062     *
063     *  @param  propertyName    The name of the property.
064     *  @param  getter  The property getter.
065     *  @param  setter  The property setter.
066     */
067    protected BulkDataAccessorBase( final String propertyName, final Getter<T> getter, final Setter<T> setter )
068    {
069        super( propertyName, getter, setter );
070    }   //  BulkDataAccessorBase()
071
072        /*---------*\
073    ====** Methods **==========================================================
074        \*---------*/
075    /**
076     *  Converts the given {@code byte} array to an instance of the property
077     *  type.
078     *
079     *  @param  source  The byte array; can be {@code null}.
080     *  @param  node    The reference to the {@code Preferences} node that
081     *      provides the value.
082     *  @return The instance, or {@code null} if the source was already
083     *      {@code null}.
084     *  @throws InvalidPreferenceValueException The preferences value cannot be
085     *      translated to the property type.
086     */
087    protected abstract T fromByteArray( final Preferences node, final byte [] source) throws InvalidPreferenceValueException;
088
089    /**
090     *  {@inheritDoc}
091     */
092    @Override
093    public void readPreference( final Preferences node ) throws BackingStoreException, InvalidPreferenceValueException
094    {
095        final var defaultValue = toByteArray( requireNonNullArgument( node, "node" ), getter().get() );
096        final var prefsValue = node.getByteArray( getPropertyName(), defaultValue );
097        final var value = fromByteArray( node, prefsValue );
098        setter().set( value );
099    }   //  readPreference()
100
101    /**
102     *  Converts the given instance of the property type into a {@code byte}
103     *  array.
104     *
105     *  @param  source  The instance; can be {@code null}.
106     *  @param  node    The reference to the {@code Preferences} node that is
107     *      used to store the preferences value.
108     *  @return The {@code byte} array, or {@code null} if the source was
109     *      already {@code null}.
110     *  @throws InvalidPreferenceValueException   The conversion failed to a
111     *      {@code byte} array failed.
112     */
113    protected abstract byte [] toByteArray( @SuppressWarnings( "unused" ) final Preferences node, final T source ) throws InvalidPreferenceValueException;
114
115    /**
116     *  {@inheritDoc}
117     */
118    @Override
119    public void writePreference( final Preferences node ) throws BackingStoreException
120    {
121        requireNonNullArgument( node, "node" );
122        final var propertyValue = getter().get();
123        if( isNull( propertyValue ) )
124        {
125            node.remove( getPropertyName() );
126        }
127        else
128        {
129            final var prefsValue = toByteArray( node, propertyValue );
130            node.putByteArray( getPropertyName(), prefsValue );
131        }
132    }   //  writePreference()
133}
134//  class BulkDataAccessorBase
135
136/*
137 *  End of File
138 */