View Javadoc

1   /***
2    *  Copyright 2003-2010 Terracotta, Inc.
3    *
4    *  Licensed under the Apache License, Version 2.0 (the "License");
5    *  you may not use this file except in compliance with the License.
6    *  You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *  Unless required by applicable law or agreed to in writing, software
11   *  distributed under the License is distributed on an "AS IS" BASIS,
12   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *  See the License for the specific language governing permissions and
14   *  limitations under the License.
15   */
16  
17  package net.sf.ehcache.config;
18  
19  /***
20   * Memory unit: byte-based
21   * @author Alex Snaps
22   */
23  public enum MemoryUnit {
24  
25      /***
26       * BYTES
27       */
28      BYTES(0, 'b') {
29          /***
30           * {@inheritDoc}
31           */
32          public long toBytes(final long amount) { return amount; }
33          /***
34           * {@inheritDoc}
35           */
36          public long toKiloBytes(final long amount) { return safeShift(amount, KILOBYTES.offset - BYTES.offset); }
37          /***
38           * {@inheritDoc}
39           */
40          public long toMegaBytes(final long amount) { return safeShift(amount, MEGABYTES.offset - BYTES.offset); }
41          /***
42           * {@inheritDoc}
43           */
44          public long toGigaBytes(final long amount) { return safeShift(amount, GIGABYTES.offset - BYTES.offset); }
45      },
46  
47      /***
48       * KILOBYTES (1024 BYTES)
49       */
50      KILOBYTES(BYTES.offset + MemoryUnit.OFFSET, 'k') {
51          /***
52           * {@inheritDoc}
53           */
54          public long toBytes(final long amount) { return safeShift(amount, BYTES.offset - KILOBYTES.offset); }
55          /***
56           * {@inheritDoc}
57           */
58          public long toKiloBytes(final long amount) { return amount; }
59          /***
60           * {@inheritDoc}
61           */
62          public long toMegaBytes(final long amount) { return safeShift(amount, MEGABYTES.offset - KILOBYTES.offset); }
63          /***
64           * {@inheritDoc}
65           */
66          public long toGigaBytes(final long amount) { return safeShift(amount, GIGABYTES.offset - KILOBYTES.offset); }
67      },
68  
69      /***
70       * MEGABYTES (1024 KILOBYTES)
71       */
72      MEGABYTES(KILOBYTES.offset + MemoryUnit.OFFSET, 'm') {
73          /***
74           * {@inheritDoc}
75           */
76          public long toBytes(final long amount) { return safeShift(amount, BYTES.offset - MEGABYTES.offset); }
77          /***
78           * {@inheritDoc}
79           */
80          public long toKiloBytes(final long amount) { return safeShift(amount, KILOBYTES.offset - MEGABYTES.offset); }
81          /***
82           * {@inheritDoc}
83           */
84          public long toMegaBytes(final long amount) { return amount; }
85          /***
86           * {@inheritDoc}
87           */
88          public long toGigaBytes(final long amount) { return safeShift(amount, GIGABYTES.offset - MEGABYTES.offset); }
89      },
90  
91      /***
92       * GIGABYTES (1024 MEGABYTES)
93       */
94      GIGABYTES(MEGABYTES.offset + MemoryUnit.OFFSET, 'g') {
95          /***
96           * {@inheritDoc}
97           */
98          public long toBytes(final long amount) { return safeShift(amount, BYTES.offset - GIGABYTES.offset); }
99          /***
100          * {@inheritDoc}
101          */
102         public long toKiloBytes(final long amount) { return safeShift(amount, KILOBYTES.offset - GIGABYTES.offset); }
103         /***
104          * {@inheritDoc}
105          */
106         public long toMegaBytes(final long amount) { return safeShift(amount, MEGABYTES.offset - GIGABYTES.offset); }
107         /***
108          * {@inheritDoc}
109          */
110         public long toGigaBytes(final long amount) { return amount; }
111     };
112 
113     private static final int OFFSET = 10;
114 
115     private        final int offset;
116     private        final char unit;
117 
118     private MemoryUnit(final int offset, final char unit) {
119         this.offset = offset;
120         this.unit = unit;
121     }
122 
123     /***
124      * Retrieves the unit character for the MemoryUnit
125      * @return the unit character
126      */
127     public char getUnit() {
128         return unit;
129     }
130 
131     /***
132      * returns the amount in bytes
133      * @param amount of the unit
134      * @return value in bytes
135      */
136     public abstract long toBytes(long amount);
137     /***
138      * returns the amount in kilobytes
139      * @param amount of the unit
140      * @return value in kilobytes
141      */
142     public abstract long toKiloBytes(long amount);
143     /***
144      * returns the amount in megabytes
145      * @param amount of the unit
146      * @return value in megabytes
147      */
148     public abstract long toMegaBytes(long amount);
149     /***
150      * returns the amount in gigabytes
151      * @param amount of the unit
152      * @return value in gigabytes
153      */
154     public abstract long toGigaBytes(long amount);
155 
156     /***
157      * Human readable value, with the added unit character as a suffix
158      * @param amount the amount to print
159      * @return the String representation
160      */
161     public String toString(final long amount) {
162         return amount + Character.toString(this.unit);
163     }
164 
165     /***
166      * Returns the MemoryUnit instance based on provided char
167      * @param unit the unit to look for
168      * @return the MemoryUnit instance matching the unit
169      * @throws IllegalArgumentException if no matching MemoryUnit matching the char
170      */
171     public static MemoryUnit forUnit(final char unit) throws IllegalArgumentException {
172         for (MemoryUnit memoryUnit : values()) {
173             if (memoryUnit.unit == unit) {
174                 return memoryUnit;
175             }
176         }
177         throw new IllegalArgumentException("'" + unit + "' suffix doesn't match any SizeUnit");
178     }
179 
180     /***
181      * Parses the unit part of a String, if no unit char available, returns {@link MemoryUnit#BYTES}
182      * @param value the String representation of an amount of memory
183      * @return the MemoryUnit instance, or BYTES if none
184      */
185     public static MemoryUnit parseUnit(final String value) {
186         if (hasUnit(value)) {
187             return forUnit(Character.toLowerCase(value.charAt(value.length() - 1)));
188         }
189         return BYTES;
190     }
191 
192     /***
193      * Parses the amount represented by the string, without caring for the unit
194      * @param value the String representation of an amount of memory
195      * @return the amount of mem in the unit represented by the potential unit char
196      * @throws NumberFormatException if not a number (with potential unit char stripped)
197      */
198     public static long parseAmount(final String value) throws NumberFormatException {
199         if (value == null) {
200             throw new NullPointerException("Value can't be null!");
201         }
202 
203         if (value.length() == 0) {
204             throw new IllegalArgumentException("Value can't be an empty string!");
205         }
206 
207         if (hasUnit(value)) {
208             return Long.parseLong(value.substring(0, value.length() - 1).trim());
209         } else {
210             return Long.parseLong(value);
211         }
212     }
213 
214     /***
215      * Parses the string for its content, returning the represented value in bytes
216      * @param value the String representation of an amount of memory
217      * @return the amount of bytes represented by the string
218      * @throws NumberFormatException if not a number (with potential unit char stripped)
219      * @throws IllegalArgumentException if no matching MemoryUnit matching the char
220      */
221     public static long parseSizeInBytes(final String value) throws NumberFormatException, IllegalArgumentException {
222         if (value.length() == 0) {
223             throw new IllegalArgumentException("Value can't be an empty string!");
224         }
225 
226         MemoryUnit memoryUnit = parseUnit(value);
227         return memoryUnit.toBytes(parseAmount(value));
228     }
229 
230     private static boolean hasUnit(final String value) {
231         if (value.length() > 0) {
232             char potentialUnit = value.charAt(value.length() - 1);
233             return potentialUnit < '0' || potentialUnit > '9';
234         }
235         return false;
236     }
237 
238     private static long safeShift(final long unit, final long shift) {
239         if (shift > 0) {
240             return unit >>> shift;
241         } else if (shift <= -1 * Long.numberOfLeadingZeros(unit)) {
242           return Long.MAX_VALUE;
243         } else {
244             return unit << -shift;
245         }
246     }
247 }