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

net.sourceforge.urin.PercentEncodingPartial Maven / Gradle / Ivy

There is a newer version: 5.2
Show newest version
/*
 * Copyright 2024 Mark Slater
 *
 * Licensed 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 net.sourceforge.urin;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import static java.util.Arrays.asList;
import static java.util.Objects.requireNonNull;
import static java.util.regex.Pattern.quote;
import static net.sourceforge.urin.CharacterSetMembershipFunction.NO_CHARACTERS;

public abstract class PercentEncodingPartial {
    PercentEncodingPartial() {
    }

    public static  PercentEncodingPartial noOp() {
        return new PercentEncodingPartial() {
            @Override
            public PercentEncoding apply(final PercentEncoding childPercentEncoding) {
                return childPercentEncoding;
            }
        };
    }

    public static  PercentEncodingPartial additionallyEncoding(final Iterable characters, final PercentEncodingPartial childPercentEncodingPartial) {
        characters.forEach(character -> requireNonNull(character, "Cannot additionally encode null Character"));
        return childPercentEncodingPartial.chain(new PercentEncodingPartial() {
            @Override
            public PercentEncoding apply(final PercentEncoding childPercentEncoding) {
                PercentEncoding result = childPercentEncoding;
                for (final char character : characters) {
                    result = result.additionallyEncoding(character);
                }
                return result;
            }
        });
    }

    public static  PercentEncodingPartial, V> percentEncodingDelimitedValue(final char delimiter, final PercentEncodingPartial childPercentEncodingPartial) {
        return childPercentEncodingPartial.chain(new PercentEncodingPartial, T>() {
            @Override
            public PercentEncoding> apply(final PercentEncoding childPercentEncoding) {
                return new PercentEncoding.PercentEncodingDelimitedValue<>(delimiter, childPercentEncoding);
            }
        });
    }

    public static PercentEncodingPartial, String> percentEncodingDelimitedValue(final char delimiter) {
        return new PercentEncodingPartial, String>() {
            @Override
            public PercentEncoding> apply(final PercentEncoding childPercentEncoding) {
                return new PercentEncoding.PercentEncodingDelimitedValue<>(delimiter, childPercentEncoding);
            }
        };
    }

    public static PercentEncodingPartial percentEncodingSubstitutedValue(final char originalCharacter, final char replacementCharacter) {
        return new PercentEncodingPartial() {
            @Override
            public PercentEncoding apply(final PercentEncoding childPercentEncoding) {
                return new PercentEncoding.PercentEncodingSubstitutedValue(originalCharacter, replacementCharacter, childPercentEncoding);
            }
        };
    }

    public static  PercentEncodingPartial transformingPercentEncodingPartial(final PercentEncodingPartial childPercentEncodingPartial, final Transformer transformer) {
        return childPercentEncodingPartial.chain(new PercentEncodingPartial() {
            @Override
            public PercentEncoding apply(final PercentEncoding childPercentEncoding) {
                return new PercentEncoding() {
                    @Override
                    public String encode(final T notEncoded) {
                        return childPercentEncoding.encode(transformer.encode(notEncoded));
                    }

                    @Override
                    public T decode(final String encoded) throws ParseException {
                        return transformer.decode(childPercentEncoding.decode(encoded));
                    }

                    @Override
                    public PercentEncoding additionallyEncoding(final char additionallyEncodedCharacter) {
                        return apply(childPercentEncoding.additionallyEncoding(additionallyEncodedCharacter));
                    }
                };
            }
        });
    }

    abstract PercentEncoding apply(PercentEncoding childPercentEncoding);

    final  PercentEncodingPartial chain(final PercentEncodingPartial superEncoder) {
        return new PercentEncodingPartial() {
            @Override
            public PercentEncoding apply(final PercentEncoding childPercentEncoding) {
                return superEncoder.apply(PercentEncodingPartial.this.apply(childPercentEncoding));
            }
        };
    }

    abstract static class PercentEncoding {
        static PercentEncoding percentEncodingString(final PercentEncoder percentEncoder) {
            return new PercentEncodingString(percentEncoder);
        }

        static  PercentEncoding> percentEncodingDelimitedValue(final char delimiter, final PercentEncoding elementPercentEncoding) {
            return new PercentEncodingDelimitedValue<>(delimiter, elementPercentEncoding);
        }

        static PercentEncoding specifiedValueEncoding(final String encodedValue, final PercentEncoding percentEncoding) {
            return new SpecifiedValueEncoding(encodedValue, percentEncoding);
        }

        public abstract String encode(ENCODES notEncoded);

        public abstract ENCODES decode(String encoded) throws ParseException;

        public abstract PercentEncoding additionallyEncoding(char additionallyEncodedCharacter);

        private static final class PercentEncodingString extends PercentEncoding {
            private final PercentEncoder percentEncoder;

            PercentEncodingString(final PercentEncoder percentEncoder) {
                this.percentEncoder = requireNonNull(percentEncoder, "Cannot instantiate PercentEncodingString with null PercentEncoder");
            }

            @Override
            public String encode(final String notEncoded) {
                return percentEncoder.encode(notEncoded);
            }

            @Override
            public String decode(final String encoded) throws ParseException {
                return percentEncoder.decode(encoded);
            }

            @Override
            public PercentEncoding additionallyEncoding(final char additionallyEncodedCharacter) {
                return new PercentEncodingString(percentEncoder.additionallyEncoding(additionallyEncodedCharacter));
            }

        }

        private static final class PercentEncodingDelimitedValue extends PercentEncoding> {
            private final char delimiter;
            private final PercentEncoding percentEncoding;

            PercentEncodingDelimitedValue(final char delimiter, final PercentEncoding percentEncoding) {
                this.delimiter = delimiter;
                this.percentEncoding = percentEncoding.additionallyEncoding(delimiter);
            }

            @Override
            public String encode(final Iterable notEncoded) {
                final Iterator notEncodedIterator = notEncoded.iterator();
                final StringBuilder result = new StringBuilder();
                while (notEncodedIterator.hasNext()) {
                    result.append(percentEncoding.encode(notEncodedIterator.next()));
                    if (notEncodedIterator.hasNext()) {
                        result.append(delimiter);
                    }
                }
                return result.toString();
            }

            @Override
            public Iterable decode(final String encoded) throws ParseException {
                final String[] components = encoded.split(quote(Character.toString(delimiter)), -1);
                final List result = new ArrayList<>(components.length);
                for (final String component : components) {
                    result.add(percentEncoding.decode(component));
                }
                return result;
            }

            @Override
            public PercentEncoding> additionallyEncoding(final char additionallyEncodedCharacter) {
                return new PercentEncodingDelimitedValue<>(delimiter, percentEncoding.additionallyEncoding(additionallyEncodedCharacter));
            }

        }

        private static class PercentEncodingSubstitutedValue extends PercentEncoding {
            private final char originalCharacter;
            private final char replacementCharacter;
            private final PercentEncoding percentEncoding;

            PercentEncodingSubstitutedValue(final char originalCharacter, final char replacementCharacter, final PercentEncoding percentEncoding) {
                this.originalCharacter = originalCharacter;
                this.replacementCharacter = replacementCharacter;
                this.percentEncoding = percentEncoding.additionallyEncoding(replacementCharacter);
            }

            @Override
            public String encode(final String notEncoded) {
                final StringBuilder result = new StringBuilder();
                final Iterator valuePartsIterator = asList(notEncoded.split(quote(Character.toString(originalCharacter)), -1)).iterator();
                while (valuePartsIterator.hasNext()) {
                    result.append(percentEncoding.encode(valuePartsIterator.next()));
                    if (valuePartsIterator.hasNext()) {
                        result.append(replacementCharacter);
                    }
                }
                return result.toString();
            }

            @Override
            public String decode(final String encoded) throws ParseException {
                final StringBuilder result = new StringBuilder();
                final String[] split = encoded.split(quote(Character.toString(replacementCharacter)), -1);
                for (int i = 0; i < split.length; i++) {
                    if (i > 0) {
                        result.append(originalCharacter);
                    }
                    result.append(percentEncoding.decode(split[i]));
                }
                return result.toString();
            }

            @Override
            public PercentEncoding additionallyEncoding(final char additionallyEncodedCharacter) {
                return new PercentEncodingSubstitutedValue(originalCharacter, replacementCharacter, percentEncoding.additionallyEncoding(additionallyEncodedCharacter));
            }

        }

        private static class SpecifiedValueEncoding extends PercentEncoding {

            private final String encodedValue;
            private final PercentEncoding percentEncoding;

            SpecifiedValueEncoding(final String encodedValue, final PercentEncoding percentEncoding) {
                this.encodedValue = requireNonNull(encodedValue, "Cannot instantiate SpecifiedValueEncoding with null encoded value");
                this.percentEncoding = requireNonNull(percentEncoding, "Cannot instantiate SpecifiedValueEncoding with null PercentEncoding");
            }

            @Override
            public String encode(final String notEncoded) {
                if (encodedValue.equals(notEncoded)) {
                    return new PercentEncoder(NO_CHARACTERS).encode(notEncoded);
                } else {
                    return percentEncoding.encode(notEncoded);
                }
            }

            @Override
            public String decode(final String encoded) throws ParseException {
                return percentEncoding.decode(encoded);
            }

            @Override
            public PercentEncoding additionallyEncoding(final char additionallyEncodedCharacter) {
                return new SpecifiedValueEncoding(encodedValue, percentEncoding.additionallyEncoding(additionallyEncodedCharacter));
            }

        }

    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy