BooleanFormatter.java
001 /*
002  * SPDX-License-Identifier: Apache-2.0
003  *
004  * Copyright 2008-2017 the original author or authors.
005  *
006  * Licensed under the Apache License, Version 2.0 (the "License");
007  * you may not use this file except in compliance with the License.
008  * You may obtain a copy of the License at
009  *
010  *     http://www.apache.org/licenses/LICENSE-2.0
011  *
012  * Unless required by applicable law or agreed to in writing, software
013  * distributed under the License is distributed on an "AS IS" BASIS,
014  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015  * See the License for the specific language governing permissions and
016  * limitations under the License.
017  */
018 package griffon.core.formatters;
019 
020 import javax.annotation.Nonnull;
021 import javax.annotation.Nullable;
022 import java.util.Arrays;
023 
024 import static griffon.util.GriffonNameUtils.isBlank;
025 import static java.util.Objects.requireNonNull;
026 
027 /**
028  @author Andres Almiray
029  @since 2.0.0
030  */
031 public class BooleanFormatter extends AbstractFormatter<Boolean> {
032     public static final String PATTERN_BOOL = "boolean";
033     public static final String PATTERN_QUERY = "query";
034     public static final String PATTERN_SWITCH = "switch";
035     public static final String DEFAULT_PATTERN = PATTERN_BOOL;
036 
037     private static final String[] PATTERNS = new String[]{
038         PATTERN_BOOL,
039         PATTERN_QUERY,
040         PATTERN_SWITCH
041     };
042 
043     public static final BooleanFormatter BOOL = new BooleanFormatter(PATTERN_BOOL);
044     public static final BooleanFormatter QUERY = new BooleanFormatter(PATTERN_QUERY);
045     public static final BooleanFormatter SWITCH = new BooleanFormatter(PATTERN_SWITCH);
046 
047     private static final BooleanFormatter[] FORMATTERS = new BooleanFormatter[]{
048         BOOL,
049         QUERY,
050         SWITCH
051     };
052 
053     @Nonnull
054     public static BooleanFormatter getInstance(@Nullable String pattern) {
055         return new BooleanFormatter(pattern);
056     }
057 
058     private final BooleanFormatterDelegate delegate;
059 
060     public BooleanFormatter() {
061         this(DEFAULT_PATTERN);
062     }
063 
064     protected BooleanFormatter(@Nullable String pattern) {
065         if (PATTERN_BOOL.equals(pattern)) {
066             delegate = new BoolBooleanFormatterDelegate();
067         else if (PATTERN_QUERY.equals(pattern)) {
068             delegate = new QueryBooleanFormatterDelegate();
069         else if (PATTERN_SWITCH.equals(pattern)) {
070             delegate = new SwitchBooleanFormatterDelegate();
071         else if (isBlank(pattern)) {
072             delegate = new BoolBooleanFormatterDelegate();
073         else {
074             throw new IllegalArgumentException("Invalid pattern '" + pattern + "'. Valid patterns are " + Arrays.toString(PATTERNS));
075         }
076     }
077 
078     @Nonnull
079     public String getPattern() {
080         return delegate.getPattern();
081     }
082 
083     @Nullable
084     public static Boolean parseBoolean(@Nullable String strthrows ParseException {
085         if (isBlank(str)) return null;
086         for (BooleanFormatter formatter : FORMATTERS) {
087             try {
088                 return formatter.parse(str);
089             catch (ParseException e) {
090                 // ignore
091             }
092         }
093         throw parseError(str, Boolean.class);
094     }
095 
096     @Nullable
097     @Override
098     public String format(@Nullable Boolean value) {
099         return value == null null : delegate.format(value);
100     }
101 
102     @Nullable
103     @Override
104     @SuppressWarnings("ConstantConditions")
105     public Boolean parse(@Nullable String strthrows ParseException {
106         return isBlank(strnull : delegate.parse(str);
107     }
108 
109     private interface BooleanFormatterDelegate {
110         @Nonnull
111         String getPattern();
112 
113         @Nonnull
114         String format(@Nonnull Boolean value);
115 
116         @Nonnull
117         Boolean parse(@Nonnull String strthrows ParseException;
118     }
119 
120     private abstract static class AbstractBooleanFormatterDelegate implements BooleanFormatterDelegate {
121         private final String pattern;
122         private final String[] tokens;
123 
124         private AbstractBooleanFormatterDelegate(String pattern, String[] tokens) {
125             this.pattern = pattern;
126             this.tokens = tokens;
127         }
128 
129         @Nonnull
130         @Override
131         public String getPattern() {
132             return pattern;
133         }
134 
135         @Nonnull
136         @Override
137         public String format(@Nonnull Boolean bool) {
138             requireNonNull(bool, "Can't format given Boolean because it's null");
139             return bool ? tokens[1: tokens[0];
140         }
141 
142         @Nonnull
143         @Override
144         public Boolean parse(@Nonnull String strthrows ParseException {
145             if (tokens[0].equalsIgnoreCase(str)) {
146                 return Boolean.FALSE;
147             else if (tokens[1].equalsIgnoreCase(str)) {
148                 return Boolean.TRUE;
149             }
150             throw parseError(str, Boolean.class);
151         }
152     }
153 
154     private static class BoolBooleanFormatterDelegate extends AbstractBooleanFormatterDelegate {
155         private BoolBooleanFormatterDelegate() {
156             super(PATTERN_BOOL, new String[]{"false""true"});
157         }
158     }
159 
160     private static class QueryBooleanFormatterDelegate extends AbstractBooleanFormatterDelegate {
161         private QueryBooleanFormatterDelegate() {
162             super(PATTERN_QUERY, new String[]{"no""yes"});
163         }
164     }
165 
166     private static class SwitchBooleanFormatterDelegate extends AbstractBooleanFormatterDelegate {
167         private SwitchBooleanFormatterDelegate() {
168             super(PATTERN_SWITCH, new String[]{"off""on"});
169         }
170     }
171 }