001 /* 002 * Copyright 2009-2013 Stephen Colebourne 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 org.joda.money.format; 017 018 import java.math.BigDecimal; 019 import java.text.ParsePosition; 020 import java.util.Locale; 021 022 import org.joda.money.BigMoney; 023 import org.joda.money.CurrencyUnit; 024 025 /** 026 * Context used when parsing money. 027 * <p> 028 * This class is mutable and intended for use by a single thread. 029 * A new instance is created for each parse. 030 */ 031 public final class MoneyParseContext { 032 033 /** 034 * The locale to parse using. 035 */ 036 private Locale locale; 037 /** 038 * The text to parse. 039 */ 040 private CharSequence text; 041 /** 042 * The text index. 043 */ 044 private int textIndex; 045 /** 046 * The text error index. 047 */ 048 private int textErrorIndex = -1; 049 /** 050 * The parsed currency. 051 */ 052 private CurrencyUnit currency; 053 /** 054 * The parsed amount. 055 */ 056 private BigDecimal amount; 057 058 /** 059 * Constructor. 060 * 061 * @param locale the locale, not null 062 * @param text the text to parse, not null 063 * @param index the current text index 064 */ 065 MoneyParseContext(Locale locale, CharSequence text, int index) { 066 this.locale = locale; 067 this.text = text; 068 this.textIndex = index; 069 } 070 071 //----------------------------------------------------------------------- 072 /** 073 * Gets the locale. 074 * 075 * @return the locale, not null 076 */ 077 public Locale getLocale() { 078 return locale; 079 } 080 081 /** 082 * Sets the locale. 083 * 084 * @param locale the locale, not null 085 */ 086 public void setLocale(Locale locale) { 087 MoneyFormatter.checkNotNull(locale, "Locale must not be null"); 088 this.locale = locale; 089 } 090 091 /** 092 * Gets the text being parsed. 093 * 094 * @return the text being parsed, never null 095 */ 096 public CharSequence getText() { 097 return text; 098 } 099 100 /** 101 * Sets the text. 102 * 103 * @param text the text being parsed, not null 104 */ 105 public void setText(CharSequence text) { 106 MoneyFormatter.checkNotNull(text, "Text must not be null"); 107 this.text = text; 108 } 109 110 /** 111 * Gets the length of the text being parsed. 112 * 113 * @return the length of the text being parsed 114 */ 115 public int getTextLength() { 116 return text.length(); 117 } 118 119 /** 120 * Gets a substring of the text being parsed. 121 * 122 * @param start the start index 123 * @param end the end index 124 * @return the substring, not null 125 */ 126 public String getTextSubstring(int start, int end) { 127 return text.subSequence(start, end).toString(); 128 } 129 130 //----------------------------------------------------------------------- 131 /** 132 * Gets the current parse position index. 133 * 134 * @return the current parse position index 135 */ 136 public int getIndex() { 137 return textIndex; 138 } 139 140 /** 141 * Sets the current parse position index. 142 * 143 * @param index the current parse position index 144 */ 145 public void setIndex(int index) { 146 this.textIndex = index; 147 } 148 149 //----------------------------------------------------------------------- 150 /** 151 * Gets the error index. 152 * 153 * @return the error index, negative if no error 154 */ 155 public int getErrorIndex() { 156 return textErrorIndex; 157 } 158 159 /** 160 * Sets the error index. 161 * 162 * @param index the error index 163 */ 164 public void setErrorIndex(int index) { 165 this.textErrorIndex = index; 166 } 167 168 /** 169 * Sets the error index from the current index. 170 */ 171 public void setError() { 172 this.textErrorIndex = textIndex; 173 } 174 175 //----------------------------------------------------------------------- 176 /** 177 * Gets the parsed currency. 178 * 179 * @return the parsed currency, null if not parsed yet 180 */ 181 public CurrencyUnit getCurrency() { 182 return currency; 183 } 184 185 /** 186 * Sets the parsed currency. 187 * 188 * @param currency the parsed currency, may be null 189 */ 190 public void setCurrency(CurrencyUnit currency) { 191 this.currency = currency; 192 } 193 194 //----------------------------------------------------------------------- 195 /** 196 * Gets the parsed amount. 197 * 198 * @return the parsed amount, null if not parsed yet 199 */ 200 public BigDecimal getAmount() { 201 return amount; 202 } 203 204 /** 205 * Sets the parsed currency. 206 * 207 * @param amount the parsed amount, may be null 208 */ 209 public void setAmount(BigDecimal amount) { 210 this.amount = amount; 211 } 212 213 //----------------------------------------------------------------------- 214 /** 215 * Checks if the parse has found an error. 216 * 217 * @return whether a parse error has occurred 218 */ 219 public boolean isError() { 220 return textErrorIndex >= 0; 221 } 222 223 /** 224 * Checks if the text has been fully parsed such that there is no more text to parse. 225 * 226 * @return true if fully parsed 227 */ 228 public boolean isFullyParsed() { 229 return textIndex == getTextLength(); 230 } 231 232 /** 233 * Checks if the context contains a currency and amount suitable for creating 234 * a monetary value. 235 * 236 * @return true if able to create a monetary value 237 */ 238 public boolean isComplete() { 239 return currency != null && amount != null; 240 } 241 242 //----------------------------------------------------------------------- 243 /** 244 * Converts the indexes to a parse position. 245 * 246 * @return the parse position, never null 247 */ 248 public ParsePosition toParsePosition() { 249 ParsePosition pp = new ParsePosition(textIndex); 250 pp.setErrorIndex(textErrorIndex); 251 return pp; 252 } 253 254 /** 255 * Converts the context to a {@code BigMoney}. 256 * 257 * @return the monetary value, never null 258 * @throws MoneyFormatException if either the currency or amount is missing 259 */ 260 public BigMoney toBigMoney() { 261 if (currency == null) { 262 throw new MoneyFormatException("Cannot convert to BigMoney as no currency found"); 263 } 264 if (amount == null) { 265 throw new MoneyFormatException("Cannot convert to BigMoney as no amount found"); 266 } 267 return BigMoney.of(currency, amount); 268 } 269 270 }