OSDN Git Service

* Add size restricted 'INTEGER' and 'ENUMERATED' types which contain a Long value.
[bm-asn1/bm-asn1.git] / jp / bitmeister / asn1 / type / builtin / INTEGER.java
index 50d1f0a..def4b97 100644 (file)
-/*
- * Copyright 2011 BitMeister Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
 package jp.bitmeister.asn1.type.builtin;
 
 import java.lang.reflect.Field;
-import java.lang.reflect.Modifier;
-import java.math.BigInteger;
-import java.util.HashMap;
 import java.util.Map;
-import java.util.Map.Entry;
 
 import jp.bitmeister.asn1.annotation.ASN1BuiltIn;
-import jp.bitmeister.asn1.annotation.ASN1Enumeration;
-import jp.bitmeister.asn1.annotation.ASN1Identifier;
 import jp.bitmeister.asn1.annotation.ASN1Tag;
-import jp.bitmeister.asn1.exception.ASN1IllegalArgument;
 import jp.bitmeister.asn1.exception.ASN1IllegalDefinition;
 import jp.bitmeister.asn1.exception.ASN1RuntimeException;
 import jp.bitmeister.asn1.processor.ASN1Visitor;
 import jp.bitmeister.asn1.type.ASN1TagClass;
 import jp.bitmeister.asn1.type.ASN1TagMode;
-import jp.bitmeister.asn1.type.ASN1Type;
-import jp.bitmeister.asn1.type.PrimitiveType;
-import jp.bitmeister.asn1.type.ValueComparable;
+import jp.bitmeister.asn1.type.AbstractInteger;
+import jp.bitmeister.asn1.type.NamedNumberMap;
 
 /**
- * Represents ASN.1 'INTEGER' type.
+ * An implementation of ASN.1 'INTEGER' type that contains {@code Long} value.
  * 
  * <p>
  * An instance of this class represents an 'INTEGER' type data, and has a
- * {@link java.math.BigInteger} value.
- * </p>
- * <p>
- * A sub-class of {@code INTEGER} can contain one or more fields annotated as
- * {@code @ASN1Enumeration}. If a sub-class of {@code INTEGER} contains
- * {@code @ASN1Enumeration} fields, the value of the data must be same as one of
- * the {@code @ASN1Enumeration} fields.
+ * {@link java.lang.Long} value. If the data needs to contain value which is
+ * bigger than {@code Long.MAX_VALUE} or smaller than {@code Long.MIN_VALUE},
+ * {@code BigINTEGER} type shall be used.
  * </p>
  * 
  * @author WATANABE, Jun. <jwat at bitmeister.jp>
  * 
- * @see ASN1Enumeration
+ * @see BigINTEGER
  */
 @ASN1BuiltIn
 @ASN1Tag(tagClass = ASN1TagClass.UNIVERSAL, value = 2, tagMode = ASN1TagMode.IMPLICIT)
-public class INTEGER extends PrimitiveType<BigInteger> implements
-               ValueComparable {
+public class INTEGER extends AbstractInteger<Long> {
 
        /**
-        * Contains the maps of enumerations for all of the sub-types of 'INTEGER'
-        * and 'ENUMERATED'.
+        * Contains the maps of enumerations for all of the sub-types of {@code INTEGER}
+        * and {@code ENUMERATED}.
         */
-       private static final Map<Class<? extends INTEGER>, Map<BigInteger, String>> NAMED_NUMBER_MAPS = new HashMap<Class<? extends INTEGER>, Map<BigInteger, String>>();
-
-       static {
-               NAMED_NUMBER_MAPS.put(INTEGER.class, new HashMap<BigInteger, String>());
-       }
+       private static final NamedNumberMap<Long> NAMED_NUMBER_MAPS = new NamedNumberMap<Long>() {
 
-       /**
-        * Returns the map of enumerations for the type. The {@code Map} maps value
-        * to identifier.
-        * 
-        * @param type
-        *            The type.
-        * @return The map of enumerations.
-        */
-       private static Map<BigInteger, String> getNamedNumberMap(
-                       Class<? extends INTEGER> type) {
-               if (NAMED_NUMBER_MAPS.containsKey(type)) {
-                       return NAMED_NUMBER_MAPS.get(type);
-               }
-               Map<BigInteger, String> map = new HashMap<BigInteger, String>();
-               for (Field f : type.getDeclaredFields()) {
-                       if (!f.isAnnotationPresent(ASN1Enumeration.class)) {
-                               continue;
-                       }
-                       final int modifier = Modifier.PUBLIC | Modifier.STATIC
-                                       | Modifier.FINAL;
-                       ASN1Identifier id = f.getAnnotation(ASN1Identifier.class);
-                       String fieldId = id != null ? id.value() : f.getName();
-                       if ((f.getModifiers() & modifier) != modifier) {
-                               ASN1IllegalDefinition ex = new ASN1IllegalDefinition();
-                               ex.setMessage(
-                                               "An enumeration must be a public static final field.",
-                                               null, type, fieldId, null);
-                               throw ex;
-                       }
-                       BigInteger value;
-                       if (f.getType() == BigInteger.class) {
-                               try {
-                                       value = (BigInteger) f.get(null);
-                               } catch (Exception e) {
-                                       ASN1RuntimeException ex = new ASN1RuntimeException();
-                                       ex.setMessage("Failed to retreave the BigInteger value.",
-                                                       e, type, fieldId, null);
-                                       throw ex;
-                               }
-                       } else if (f.getType() == int.class || f.getType() == long.class) {
+               @Override
+               public Long getKeyValue(Field f) {
+                       Long value;
+                       if (f.getType() == int.class || f.getType() == long.class) {
                                try {
-                                       value = BigInteger.valueOf(f.getLong(null));
+                                       value = f.getLong(null);
                                } catch (Exception e) {
-                                       ASN1RuntimeException ex = new ASN1RuntimeException();
-                                       ex.setMessage("Failed to convert the value to BigInteger.",
-                                                       e, type, fieldId, null);
+                                       ASN1RuntimeException ex = new ASN1RuntimeException(
+                                                       "Failed to retreave the Long value.");
                                        throw ex;
                                }
                        } else {
-                               ASN1IllegalDefinition ex = new ASN1IllegalDefinition();
-                               ex.setMessage(
-                                               "An enumeration must be an 'int', 'long' or 'BigInteger' field.",
-                                               null, type, fieldId, null);
-                               throw ex;
-                       }
-                       if (map.containsKey(value)) {
-                               ASN1IllegalDefinition ex = new ASN1IllegalDefinition();
-                               ex.setMessage(
-                                               "Each number of enumerations shall be distinct from all other enumerations in the type.",
-                                               null, type, fieldId, null);
+                               ASN1IllegalDefinition ex = new ASN1IllegalDefinition(
+                                               "An enumeration of INTEGER type must be an 'int' or a 'long' field.");
                                throw ex;
                        }
-                       map.put(value, fieldId);
+                       return value;
                }
-               @SuppressWarnings("unchecked")
-               Class<? extends INTEGER> parent = (Class<? extends INTEGER>) type
-                               .getSuperclass();
-               if (parent == ENUMERATED.class) {
-                       if (map.isEmpty()) {
-                               ASN1IllegalDefinition ex = new ASN1IllegalDefinition();
-                               ex.setMessage(
-                                               "ENUMERATED type shall have at least one enumeration item.",
-                                               null, type, null, null);
-                               throw ex;
-                       }
-               } else if (parent != INTEGER.class) {
-                       if (!map.isEmpty()) {
-                               ASN1IllegalDefinition ex = new ASN1IllegalDefinition();
-                               ex.setMessage(
-                                               "A class that does not extend 'INTEGER' or 'ENUMERATED' directly, can not have own enumerations.",
-                                               null, type, null, null);
-                               throw ex;
-                       }
-                       map = getNamedNumberMap(parent);
-               }
-               NAMED_NUMBER_MAPS.put(type, map);
-               return map;
+               
+       };
+
+       static {
+               NAMED_NUMBER_MAPS.putEmptyMap(INTEGER.class);
        }
 
        /**
@@ -165,17 +69,6 @@ public class INTEGER extends PrimitiveType<BigInteger> implements
        }
 
        /**
-        * Instantiates an {@code INTEGER} and initialize it with the
-        * {@code BigInteger} value.
-        * 
-        * @param value
-        *            The value to be assigned.
-        */
-       public INTEGER(BigInteger value) {
-               set(value);
-       }
-
-       /**
         * Instantiates an {@code INTEGER} and initialize it with the {@code long}
         * value.
         * 
@@ -186,126 +79,47 @@ public class INTEGER extends PrimitiveType<BigInteger> implements
                set(value);
        }
 
-       /*
-        * (non-Javadoc)
-        * 
-        * @see jp.bitmeister.asn1.type.PrimitiveType#set(null)
+       /* (non-Javadoc)
+        * @see jp.bitmeister.asn1.type.AbstractInteger#getNamedNumberMap()
         */
        @Override
-       public void set(BigInteger value) {
-               Map<BigInteger, String> map = getNamedNumberMap(getClass());
-               if (!map.isEmpty() && !map.containsKey(value)) {
-                       ASN1IllegalArgument ex = new ASN1IllegalArgument();
-                       ex.setMessage(
-                                       "Invalid value '"
-                                                       + value
-                                                       + "'. If a class has enumerations, the value must be same as one of them.",
-                                       null, getClass(), null, null);
-                       throw ex;
-               }
-               super.set(value);
+       public Map<Long, String> getNamedNumberMap() {
+               return NAMED_NUMBER_MAPS.getNamedNumberMap(getClass());
        }
 
-       /**
-        * Sets the {@code long} value to this data.
-        * 
-        * @param value
-        *            The value to be assigned.
-        */
-       public void set(long value) {
-               set(BigInteger.valueOf(value));
-       }
-
-       /**
-        * Sets the value specified by the name of number to this data.
-        * 
-        * @param nameOfNumber
-        *            The name of number.
-        */
-       public void set(String nameOfNumber) {
-               for (Entry<BigInteger, String> e: getNamedNumberMap(getClass()).entrySet()) {
-                       if (e.getValue().equals(nameOfNumber)) {
-                               set(e.getKey());
-                               return;
-                       }
-               }
-               ASN1IllegalArgument e = new ASN1IllegalArgument();
-               e.setMessage("The name '" + nameOfNumber + "' is not defined in this type.", null, getClass(), null, null);
-               throw e;
-       }
-
-       /**
-        * Returns an identifier related to the value of this data if the type has
-        * {@code @ASN1Enumeration} fields.
-        * 
-        * @return An identifier related to the value.
+       /* (non-Javadoc)
+        * @see jp.bitmeister.asn1.type.ASN1Type#accept(jp.bitmeister.asn1.processor.ASN1Visitor)
         */
-       public String identifier() {
-               return getNamedNumberMap(getClass()).get(value());
+       @Override
+       public <R, E extends Throwable> R accept(ASN1Visitor<R, E> visitor)
+                       throws E {
+               return visitor.visit(this);
        }
 
-       /**
-        * Tests if the value of this data is in the range of {@code long} value.
-        * 
-        * @return {@code true} when the value of this data is in the range of
-        *         {@code long}.
+       /* (non-Javadoc)
+        * @see jp.bitmeister.asn1.type.AbstractInteger#isLongValue()
         */
+       @Override
        public boolean isLongValue() {
-               return value().compareTo(BigInteger.valueOf(Long.MIN_VALUE)) >= 0
-                               && value().compareTo(BigInteger.valueOf(Long.MAX_VALUE)) <= 0;
-       }
-
-       /**
-        * Tests if the value of this data is in the range of {@code int} value.
-        * 
-        * @return {@code true} when the value of this data is in the range of
-        *         {@code int}.
-        */
-       public boolean isIntValue() {
-               return value().compareTo(BigInteger.valueOf(Integer.MIN_VALUE)) >= 0
-                               && value().compareTo(BigInteger.valueOf(Integer.MAX_VALUE)) <= 0;
-       }
-
-       /**
-        * Returns a {@code long} value that converted from the value of this data.
-        * 
-        * @return A {@code long} value.
-        */
-       public long longValue() {
-               return value().longValue();
-       }
-
-       /**
-        * Returns an {@code int} value that converted from the value of this data.
-        * 
-        * @return An {@code int} value.
-        */
-       public int intValue() {
-               return value().intValue();
+               return true;
        }
 
-       /*
-        * (non-Javadoc)
-        * 
-        * @see
-        * jp.bitmeister.asn1.type.ValueComparable#compareTo(jp.bitmeister.asn1.
-        * type.ASN1Type)
+       /* (non-Javadoc)
+        * @see jp.bitmeister.asn1.type.AbstractInteger#isIntValue()
         */
        @Override
-       public int compareTo(ASN1Type other) {
-               return value().compareTo(((INTEGER) other).value());
+       public boolean isIntValue() {
+               return Integer.MIN_VALUE <= value() && value() <= Integer.MAX_VALUE;
        }
-
+       
        /*
         * (non-Javadoc)
         * 
-        * @see
-        * jp.bitmeister.asn1.type.ASN1Type#accept(jp.bitmeister.asn1.processor.
-        * ASN1Visitor)
+        * @see jp.bitmeister.asn1.type.AbstractInteger#isEnum()
         */
        @Override
-       public <R, E extends Throwable> R accept(ASN1Visitor<R, E> visitor) throws E {
-               return visitor.visit(this);
+       protected boolean isEnum() {
+               return false;
        }
 
 }