View Javadoc

1   package com.lexicalscope.jewel.cli;
2   
3   import static java.util.Arrays.asList;
4   
5   import java.util.List;
6   
7   import com.lexicalscope.fluentreflection.FluentMethod;
8   import com.lexicalscope.jewel.cli.specification.OptionSpecification;
9   import com.lexicalscope.jewel.cli.specification.SpecificationMultiplicity;
10  
11  /*
12   * Copyright 2012 Tim Wood
13   *
14   * Licensed under the Apache License, Version 2.0 (the "License");
15   * you may not use this file except in compliance with the License.
16   * You may obtain a copy of the License at
17   *
18   * http://www.apache.org/licenses/LICENSE-2.0
19   *
20   * Unless required by applicable law or agreed to in writing, software
21   * distributed under the License is distributed on an "AS IS" BASIS,
22   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
23   * See the License for the specific language governing permissions and
24   * limitations under the License.
25   */
26  
27  abstract class AbstractOptionSpecification implements OptionSpecification, Comparable<OptionSpecification> {
28      protected final OptionAdapter annotation;
29      private final List<String> defaultValue;
30  
31      public AbstractOptionSpecification(final OptionAdapter annotation) {
32          this.annotation = annotation;
33  
34          if (annotation.defaultToNull() && annotation.hasDefaultValue())
35          {
36              throw new InvalidOptionSpecificationException("option cannot have null default and non-null default value: "
37                      + annotation.method());
38          }
39          else if (annotation.defaultToNull())
40          {
41              if (annotation.isMultiValued())
42              {
43                  defaultValue = null;
44              }
45              else
46              {
47                  defaultValue = asList((String) null);
48              }
49          }
50          else if (annotation.hasDefaultValue())
51          {
52              defaultValue = asList(annotation.defaultValue());
53          }
54          else
55          {
56              defaultValue = null;
57          }
58  
59          if(hasExactCount() && exactly() < minimum() || exactly() > maximum())
60          {
61              throw new InvalidOptionSpecificationException("option has maximum and minimum and exact count which can never be satisfied: "
62                      + annotation.method());
63          }
64          else if(minimum() > maximum())
65          {
66              throw new InvalidOptionSpecificationException("minimum cannot be greater than maximum: "
67                      + annotation.method());
68          }
69          else if(maximum() < 0)
70          {
71              throw new InvalidOptionSpecificationException("maximum must not be less than zero: "
72                      + annotation.method());
73          }
74      }
75  
76      @Override public final List<String> getDefaultValue() {
77          return defaultValue;
78      }
79  
80      @Override public final boolean hasDefaultValue() {
81          return getDefaultValue() != null || annotation.defaultToNull();
82      }
83  
84      @Override public final String getDescription() {
85          return annotation.description();
86      }
87  
88      @Override public final Class<?> getType() {
89          return annotation.getValueType().classUnderReflection();
90      }
91  
92      @Override public final boolean isMultiValued() {
93          return annotation.isMultiValued();
94      }
95  
96      @Override public final boolean isOptional() {
97          return getOptionalityMethod() != null || isBoolean() || hasDefaultValue();
98      }
99  
100     public abstract boolean isBoolean();
101 
102     @Override public final String getCanonicalIdentifier() {
103         return getMethod().property();
104     }
105 
106     @Override public final FluentMethod getMethod() {
107         return annotation.method();
108     }
109 
110     @Override public final FluentMethod getOptionalityMethod() {
111         return annotation.correspondingOptionalityMethod();
112     }
113 
114     @Override public final int compareTo(final OptionSpecification other) {
115         return getCanonicalIdentifier().compareTo(other.getCanonicalIdentifier());
116     }
117 
118     @Override public final boolean isHidden() {
119         return annotation.isHidden();
120     }
121 
122     @Override public boolean allowedThisManyValues(final int count) {
123         if(count == 0 && !hasValue())
124         {
125             return true;
126         }
127         else if(count == 1 && hasValue() && !isMultiValued())
128         {
129             return true;
130         }
131         else if(isMultiValued() && hasExactCount())
132         {
133             return count == exactly();
134         }
135         else if(isMultiValued())
136         {
137             return minimum() <= count && count <= maximum();
138         }
139         return false;
140     }
141 
142     @Override
143    public final int maximum() {
144         return annotation.maximum();
145     }
146 
147     @Override
148    public final int minimum() {
149         return annotation.minimum();
150     }
151 
152     @Override
153    public final int exactly() {
154         return annotation.exactly();
155     }
156 
157     @Override
158    public final boolean hasExactCount() {
159         return annotation.exactly() >= 0;
160     }
161 
162     @Override public <T> T compareCountToSpecification(
163             final int valueCount,
164             final SpecificationMultiplicity<T> specificationMultiplicity) {
165         if(!hasValue() && valueCount > 0) {
166             return specificationMultiplicity.expectedNoneGotSome();
167         } else if(!isMultiValued() && hasValue() && valueCount == 0) {
168             return specificationMultiplicity.expectedOneGotNone();
169         } else if(!isMultiValued() && valueCount > 1) {
170             return specificationMultiplicity.expectedOneGotSome();
171         } else if(isMultiValued()) {
172             if(hasExactCount() && valueCount != exactly()) {
173                 if(valueCount < exactly()) {
174                     return specificationMultiplicity.expectedExactGotTooFew(exactly(), valueCount);
175                 } else {
176                     return specificationMultiplicity.expectedExactGotTooMany(exactly(), valueCount);
177                 }
178             } else if(valueCount < minimum()) {
179                 return specificationMultiplicity.expectedMinimumGotTooFew(minimum(), valueCount);
180             } else if(valueCount > maximum()) {
181                 return specificationMultiplicity.expectedMaximumGotTooMany(maximum(), valueCount);
182             }
183         }
184         return specificationMultiplicity.allowed();
185     }
186 
187     @Override public int maximumArgumentConsumption() {
188         if(isMultiValued()) {
189             if(hasExactCount()) {
190                 return exactly();
191             } else {
192                 return maximum();
193             }
194         } else if (hasValue()) {
195             return 1;
196         }
197         return 0;
198     }
199 }