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