Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add JavaDoc #39

Merged
merged 13 commits into from
Aug 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,21 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* A static access point for the default {@link ServiceBindingAccessor}. The statically stored instance inside this
* class can both be retrieved ({@link DefaultServiceBindingAccessor#getInstance()}) <bold>and</bold> manipulated
* ({@link DefaultServiceBindingAccessor#setInstance(ServiceBindingAccessor)}). Applications might want to overwrite the
* default instance during startup to tweak the default behavior of libraries that are relying on it. <br>
* <bold>Please note:</bold> It is considered best practice to offer APIs that accept a dedicated
* {@link ServiceBindingAccessor} instance instead of using the globally available instance stored inside this class.
* For example, libraries that are using {@link ServiceBindingAccessor}s should offer APIs such as the following:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that if you offer to manage the global state there is a good chance people will use that, regardless of what the javadoc states 😉

Anyhow, for that purpose the naming "accessor" sounds somewhat odd..

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Anyhow, for that purpose the naming "accessor" sounds somewhat odd..

I've created an issue to consider renaming the Accessors.

*
* <pre>
* public ReturnType doSomethingWithServiceBindings( @Nonnull final ServiceBindingAccessor accessor );
* </pre>
*
* If that is, for some reason, not feasible, only then should this static default instance be used.
*/
public final class DefaultServiceBindingAccessor
{
@Nonnull
Expand All @@ -28,12 +43,33 @@ private DefaultServiceBindingAccessor()
throw new IllegalStateException("This utility class must not be instantiated.");
}

/**
* Returns the statically stored {@link ServiceBindingAccessor} instance. This instance can be changed at any time
* by using {@link DefaultServiceBindingAccessor#setInstance(ServiceBindingAccessor)}. <br>
* By default, the returned {@link ServiceBindingAccessor} will be assembled in the following way:
* <ol>
* <li>Use the {@link ServiceLoader} to find implementations of {@link ServiceBindingAccessor}.</li>
* <li>Combine instances of the found implementations using the {@link ServiceBindingMerger} (the merging strategy
* used is {@link ServiceBindingMerger#KEEP_EVERYTHING}).</li>
* <li>Wrap the resulting instance of {@link ServiceBindingMerger} into a {@link SimpleServiceBindingCache}.</li>
* </ol>
*
* @return The statically stored {@link ServiceBindingAccessor} instance.
*/
@Nonnull
public static ServiceBindingAccessor getInstance()
{
return instance;
}

/**
* Overwrites the statically stored {@link ServiceBindingAccessor} instance.
*
* @param accessor
* The {@link ServiceBindingAccessor} instance that should be returned by
* {@link DefaultServiceBindingAccessor#getInstance()}. If {@code accessor} is {@code null}, the default
* instance will be used (see {@link DefaultServiceBindingAccessor#getInstance()} for more details).
*/
public static void setInstance( @Nullable final ServiceBindingAccessor accessor )
{
if( accessor != null ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,19 @@

import com.sap.cloud.environment.servicebinding.api.exception.ServiceBindingAccessException;

/**
* Represents a source for {@link ServiceBinding}s.
*/
@FunctionalInterface
public interface ServiceBindingAccessor
{
/**
* Retrieves all {@link ServiceBinding}s that are accessible for this {@link ServiceBindingAccessor}.
*
* @return All accessible {@link ServiceBinding}s.
* @throws ServiceBindingAccessException
* Thrown if anything went wrong while loading the {@link ServiceBinding}s.
*/
@Nonnull
List<ServiceBinding> getServiceBindings()
throws ServiceBindingAccessException;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,31 @@

import javax.annotation.Nonnull;

/**
* A {@link ServiceBindingAccessor} that merges the result of multiple other {@link ServiceBindingAccessor}s. This is
* done in the following manner:
* <ol>
* <li>Create an empty {@link java.util.Set} of {@link ServiceBinding}s - this is the final result that should be
* returned by {@link #getServiceBindings()}.</li>
* <li>For each delegate {@link ServiceBindingAccessor}:</li>
* <ol>
* <li>Call {@link ServiceBindingAccessor#getServiceBindings()}.</li>
* <li>For each {@link ServiceBinding}:</li>
* <ol>
* <li>Check whether the given {@link ServiceBinding} already exists<b>*</b> in the result {@link java.util.Set}.</li>
* <li>If the {@link ServiceBinding} does not yet exist, add it to the result.</li>
* </ol>
* </ol>
* </ol>
* <b>*:</b> This class uses the {@link EqualityComparer} to determine whether a given {@link ServiceBinding} already
* exists in the result {@link java.util.Set}.
*/
public class ServiceBindingMerger implements ServiceBindingAccessor
Johannes-Schneider marked this conversation as resolved.
Show resolved Hide resolved
{
/**
* A {@link EqualityComparer} that always evaluates to {@code false}. Therefore, all {@link ServiceBinding}s will be
* included in the combined result set.
*/
@Nonnull
public static final EqualityComparer KEEP_EVERYTHING = ( a, b ) -> false;

Expand All @@ -21,6 +44,17 @@ public class ServiceBindingMerger implements ServiceBindingAccessor
@Nonnull
private final EqualityComparer equalityComparer;

/**
* Initializes a new {@link ServiceBindingMerger} instance. It will use the given {@code equalityComparer} to
* combine the individual {@link ServiceBinding}s returned from the given {@code accessors}.
Johannes-Schneider marked this conversation as resolved.
Show resolved Hide resolved
*
* @param accessors
* The {@link ServiceBindingAccessor}s that should be used to get the actual {@link ServiceBinding}s
* from.
* @param equalityComparer
* The {@link EqualityComparer} to check whether a given {@link ServiceBinding} is already part of the
* combined result set.
*/
public ServiceBindingMerger(
@Nonnull final Collection<ServiceBindingAccessor> accessors,
@Nonnull final EqualityComparer equalityComparer )
Expand Down Expand Up @@ -56,9 +90,23 @@ public List<ServiceBinding> getServiceBindings()
return existingBindings.stream().anyMatch(contained -> equalityComparer.areEqual(contained, newBinding));
}

/**
* Represents a method object that is capable of comparing two instances of {@link ServiceBinding}. An instance of
* this interface will be used when checking whether a given {@link ServiceBinding} is already contained in the
* combined set of {@link ServiceBinding}s.
*/
@FunctionalInterface
public interface EqualityComparer
Johannes-Schneider marked this conversation as resolved.
Show resolved Hide resolved
{
/**
* Determines whether the given {@link ServiceBinding} instances ({@code a} and {@code b}) are equal.
*
* @param a
* The first {@link ServiceBinding} instance.
* @param b
* The second {@link ServiceBinding} instance.
* @return {@code true} if {@code a} and {@code b} are equal, {@code false} otherwise.
*/
boolean areEqual( @Nonnull final ServiceBinding a, @Nonnull final ServiceBinding b );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@

import com.sap.cloud.environment.servicebinding.api.exception.ServiceBindingAccessException;

/**
* A {@link ServiceBindingAccessor} that caches the result of an other {@link ServiceBindingAccessor} for a certain
* amount of time.
*/
public class SimpleServiceBindingCache implements ServiceBindingAccessor
{
@Nonnull
Expand Down Expand Up @@ -51,6 +55,13 @@ public class SimpleServiceBindingCache implements ServiceBindingAccessor
@Nullable
private LocalDateTime lastCacheRenewal = null;

/**
* Initializes a new {@link SimpleServiceBindingCache} instance that retrieves {@link ServiceBinding}s from the
* given {@code delegateAccessor} and caches them for 5 minutes.
*
* @param delegateAccessor
* The {@link ServiceBindingAccessor} to retrieve the {@link ServiceBinding}s from.
*/
public SimpleServiceBindingCache( @Nonnull final ServiceBindingAccessor delegateAccessor )
{
this(delegateAccessor, DEFAULT_CACHE_DURATION, DEFAULT_LOCAL_DATE_TIME_SUPPLIER);
Expand All @@ -66,6 +77,15 @@ public SimpleServiceBindingCache( @Nonnull final ServiceBindingAccessor delegate
this.localDateTimeSupplier = localDateTimeSupplier;
}

/**
* Initializes a new {@link SimpleServiceBindingCache} instance that retrieves {@link ServiceBinding}s from the
* given {@code delegateAccessor} and caches them for the given {@code cacheDuration}.
*
* @param delegateAccessor
* The {@link ServiceBindingAccessor} to retrieve the {@link ServiceBinding}s from.
* @param cacheDuration
* The cahing {@link Duration}.
*/
public SimpleServiceBindingCache(
@Nonnull final ServiceBindingAccessor delegateAccessor,
@Nonnull final Duration cacheDuration )
Expand Down Expand Up @@ -133,6 +153,9 @@ private boolean isExpired( @Nonnull final Temporal now )
return cacheDuration.minus(durationSinceLastCacheRenewal).isNegative();
}

/**
* Invalidate the cache.
*/
public void invalidate()
{
logger.debug("Invalidating service binding cache.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,47 @@

import javax.annotation.Nonnull;

/**
* A {@link RuntimeException} that is thrown if anything goes wrong while accessing
* {@link com.sap.cloud.environment.servicebinding.api.ServiceBinding}s.
*/
public class ServiceBindingAccessException extends RuntimeException
{
private static final long serialVersionUID = 8589108462580396260L;

public ServiceBindingAccessException()
{
}

/**
* Initializes a new {@link ServiceBindingAccessException} instance with a dedicated {@code message}.
*
* @param message
* The exception message.
*/
public ServiceBindingAccessException( @Nonnull final String message )
{
super(message);
}

public ServiceBindingAccessException( @Nonnull final String message, @Nonnull final Throwable cause )
/**
* Initializes a new {@link ServiceBindingAccessException} instance with a dedicated {@code cause}.
*
* @param cause
* The exception cause.
*/
public ServiceBindingAccessException( @Nonnull final Throwable cause )
{
super(message, cause);
super(cause);
}

public ServiceBindingAccessException( @Nonnull final Throwable cause )
/**
* Initializes a new {@link ServiceBindingAccessException} instance with a dedicated {@code message} and
* {@code cause}.
*
* @param message
* The exception message.
* @param cause
* The exception cause.
*/
public ServiceBindingAccessException( @Nonnull final String message, @Nonnull final Throwable cause )
{
super(cause);
super(message, cause);
}
}
Loading