net.sourceforge.urin.PercentEncodingPartial Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of urin Show documentation
Show all versions of urin Show documentation
Urin is an open source URI generator and parser written in Java.
/*
* 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