X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;f=jp%2Fbitmeister%2Fasn1%2Fpojo%2FPojoEncoder.java;fp=jp%2Fbitmeister%2Fasn1%2Fpojo%2FPojoEncoder.java;h=e28831224e2d30ce37483d57817d060c670d1655;hb=624b226143b8c23308c2ca108e16e02df46b178b;hp=0000000000000000000000000000000000000000;hpb=845441a67dbe1e8780b9f6704395d99c60a40cec;p=bm-asn1%2Fbm-asn1.git diff --git a/jp/bitmeister/asn1/pojo/PojoEncoder.java b/jp/bitmeister/asn1/pojo/PojoEncoder.java new file mode 100644 index 0000000..e288312 --- /dev/null +++ b/jp/bitmeister/asn1/pojo/PojoEncoder.java @@ -0,0 +1,541 @@ +/* + * Copyright 2011-2012 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.pojo; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; + +import jp.bitmeister.asn1.codec.ASN1Encoder; +import jp.bitmeister.asn1.exception.ASN1DecodingException; +import jp.bitmeister.asn1.exception.ASN1EncodingException; +import jp.bitmeister.asn1.exception.ASN1IllegalArgument; +import jp.bitmeister.asn1.pojo.annotation.ASN1JavaList; +import jp.bitmeister.asn1.pojo.annotation.ASN1JavaObject; +import jp.bitmeister.asn1.processor.ASN1Visitor; +import jp.bitmeister.asn1.processor.ASN1VisitorAdaptor; +import jp.bitmeister.asn1.type.ASN1Type; +import jp.bitmeister.asn1.type.CollectionType; +import jp.bitmeister.asn1.type.ConstructiveType; +import jp.bitmeister.asn1.type.ElementSpecification; +import jp.bitmeister.asn1.type.SelectiveType; +import jp.bitmeister.asn1.type.StringType; +import jp.bitmeister.asn1.type.StructuredType; +import jp.bitmeister.asn1.type.TimeType; +import jp.bitmeister.asn1.type.UnknownType; +import jp.bitmeister.asn1.type.builtin.ANY; +import jp.bitmeister.asn1.type.builtin.BIT_STRING; +import jp.bitmeister.asn1.type.builtin.BOOLEAN; +import jp.bitmeister.asn1.type.builtin.BigENUMERATED; +import jp.bitmeister.asn1.type.builtin.BigINTEGER; +import jp.bitmeister.asn1.type.builtin.CHOICE; +import jp.bitmeister.asn1.type.builtin.ENUMERATED; +import jp.bitmeister.asn1.type.builtin.INTEGER; +import jp.bitmeister.asn1.type.builtin.NULL; +import jp.bitmeister.asn1.type.builtin.OBJECT_IDENTIFIER; +import jp.bitmeister.asn1.type.builtin.OCTET_STRING; +import jp.bitmeister.asn1.type.builtin.REAL; +import jp.bitmeister.asn1.type.builtin.RELATIVE_OID; +import jp.bitmeister.asn1.type.builtin.SEQUENCE; +import jp.bitmeister.asn1.type.builtin.SEQUENCE_OF; +import jp.bitmeister.asn1.type.builtin.SET; +import jp.bitmeister.asn1.type.builtin.SET_OF; +import jp.bitmeister.asn1.value.BinString; + +/** + * ASN.1 to POJO data encoder. + * + *

+ * {@code PojoEncoder} is an implementation of {@code ASN1Encoder}. It + * translates an ASN.1 data to a POJO data. Correspondence of an ASN.1 class to + * a POJO class is indicated by {@code @ASN1JavaObject} annotation. + *

+ * + * @author WATANABE, Jun. + * + * @see ASN1Encoder + * @see PojoDecoder + * @see ASN1JavaObject + */ +public class PojoEncoder implements ASN1Encoder { + + /** + * Destination of translation. + */ + private Object object; + + /** + * Instantiates {@code PojoEncoder} with a destination object. + * + * @param object + * The {@code @ASN1JavaObject} object. + */ + public PojoEncoder(Object object) { + this.object = object; + } + + /** + * Translates an ASN.1 data to corresponding POJO data. + * + * @param data + * The ASN.1 data to be translated. + * @return 0 + * @throws ASN1EncodingException + * When an error occurred while the encoding process. + */ + public int encode(ASN1Type data) throws ASN1EncodingException { + try { + if (data.accept(new StructureEncoder(object)) == null) { + ASN1EncodingException ex = new ASN1EncodingException(); + ex.setMessage( + "Only structured classes (SEQUENCE, SET, CHOICE) can be translated to POJO.", + null, data.getClass(), null, data); + throw ex; + } + } catch (Exception e) { + ASN1EncodingException ex = new ASN1EncodingException(); + ex.setMessage("Exception thrown while encoding process.", e, + data.getClass(), null, data); + throw ex; + } + return 0; + } + + /** + * Internal processor class that processes {@code @ASN1JavaObject} class. + * + * @author WATANABE, Jun. + * + */ + private class StructureEncoder extends + ASN1VisitorAdaptor { + + /** + * Destination. + */ + private Object object; + + /** + * Instantiates {@code StructureEncoder} with a destination object. + * + * @param object + * The {@code @ASN1JavaObject} object. + */ + StructureEncoder(Object object) { + this.object = object; + } + + /* + * (non-Javadoc) + * + * @see + * jp.bitmeister.asn1.processor.ASN1VisitorAdaptor#visit(jp.bitmeister + * .asn1.type.builtin.CHOICE) + */ + @Override + public Boolean visit(CHOICE data) throws Exception { + processSelective(data); + return true; + } + + /* + * (non-Javadoc) + * + * @see + * jp.bitmeister.asn1.processor.ASN1VisitorAdaptor#visit(jp.bitmeister + * .asn1.type.builtin.SEQUENCE) + */ + @Override + public Boolean visit(SEQUENCE data) throws Exception { + processConstructive(data); + return true; + } + + /* + * (non-Javadoc) + * + * @see + * jp.bitmeister.asn1.processor.ASN1VisitorAdaptor#visit(jp.bitmeister + * .asn1.type.builtin.SET) + */ + @Override + public Boolean visit(SET data) throws Exception { + processConstructive(data); + return true; + } + + /** + * Processes constructive type (i.e. 'SEQUENCE' and 'SET') object. + * + * @param data + * The ASN.1 constructive type object. + * @throws Exception + * When an error occurred while translation process. + */ + private void processConstructive(ConstructiveType data) + throws Exception { + PojoSpecification spec = PojoSpecification.getSpecification(object + .getClass()); + if (!spec.checkTarget(data.getClass())) { + ASN1IllegalArgument ex = new ASN1IllegalArgument(); + ex.setMessage("Incompatible ASN.1 type data is specified.", + null, data.getClass(), null, null); + throw ex; + } + for (ElementSpecification e : data.getElementTypeList()) { + Field field = spec.getField(e); + if (field == null) { + continue; + } + ASN1Type component = data.getComponent(e); + if (component != null) { + + field.set(object, + component.accept(new ElementEncoder(field))); + } + } + } + + /** + * Processes selective type (i.e. 'CHOICE') object. + * + * @param data + * The ASN.1 selective type object. + * @throws Exception + * When an error occurred while translation process. + */ + private void processSelective(SelectiveType data) throws Exception { + PojoSpecification spec = PojoSpecification.getSpecification(object + .getClass()); + if (!spec.checkTarget(data.getClass())) { + ASN1IllegalArgument ex = new ASN1IllegalArgument(); + ex.setMessage("Incompatible ASN.1 type data is specified.", + null, data.getClass(), null, null); + throw ex; + } + String selection = data.selectedIdentifier(); + Field field = spec.getField(data.getElement(selection)); + if (field != null) { + field.set(object, + data.selectedValue().accept(new ElementEncoder(field))); + } + } + + /** + * Internal processor class that processes {@code @ASN1JavaField} field. + * + * @author WATANABE, Jun. + * + */ + private class ElementEncoder implements ASN1Visitor { + + /** + * Destination field. + */ + Field field; + + /** + * Instantiates {@code ElementEncoder} with a destination field. + * + * @param field + * The destination field. + */ + ElementEncoder(Field field) { + this.field = field; + } + + /* + * (non-Javadoc) + * + * @see + * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister. + * asn1.type.builtin.BOOLEAN) + */ + public Object visit(BOOLEAN data) throws Exception { + return data.value(); + } + + /* + * (non-Javadoc) + * + * @see + * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister. + * asn1.type.builtin.INTEGER) + */ + public Object visit(INTEGER data) throws Exception { + return data.value(); + } + + /* + * (non-Javadoc) + * + * @see + * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister. + * asn1.type.builtin.BigINTEGER) + */ + public Object visit(BigINTEGER data) throws Exception { + return data.longValue(); + } + + /* + * (non-Javadoc) + * + * @see + * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister. + * asn1.type.builtin.BIT_STRING) + */ + public Object visit(BIT_STRING data) throws Exception { + return new BinString(data.value()).toByteArray(); + } + + /* + * (non-Javadoc) + * + * @see + * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister. + * asn1.type.builtin.OCTET_STRING) + */ + public Object visit(OCTET_STRING data) throws Exception { + byte[] value = new byte[data.size()]; + System.arraycopy(data.value(), 0, value, 0, value.length); + return value; + } + + /* + * (non-Javadoc) + * + * @see + * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister. + * asn1.type.builtin.NULL) + */ + public Object visit(NULL data) throws Exception { + return new Object(); + } + + /* + * (non-Javadoc) + * + * @see + * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister. + * asn1.type.builtin.OBJECT_IDENTIFIER) + */ + public Object visit(OBJECT_IDENTIFIER data) throws Exception { + int[] value = new int[data.value().size()]; + for (int i = 0; i < value.length; i++) { + value[i] = data.value().get(i); + } + return value; + } + + /* + * (non-Javadoc) + * + * @see + * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister. + * asn1.type.builtin.REAL) + */ + public Object visit(REAL data) throws Exception { + return data.value(); + } + + /* + * (non-Javadoc) + * + * @see + * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister. + * asn1.type.builtin.ENUMERATED) + */ + public Object visit(ENUMERATED data) throws Exception { + return data.value(); + } + + /* + * (non-Javadoc) + * + * @see + * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister. + * asn1.type.builtin.BigENUMERATED) + */ + public Object visit(BigENUMERATED data) throws Exception { + return data.longValue(); + } + + /* + * (non-Javadoc) + * + * @see + * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister. + * asn1.type.builtin.RELATIVE_OID) + */ + public Object visit(RELATIVE_OID data) throws Exception { + int[] value = new int[data.value().size()]; + for (int i = 0; i < value.length; i++) { + value[i] = data.value().get(i); + } + return value; + } + + /* + * (non-Javadoc) + * + * @see + * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister. + * asn1.type.builtin.ANY) + */ + public Object visit(ANY data) throws Exception { + return data.value().accept(new ElementEncoder(field)); + } + + /* + * (non-Javadoc) + * + * @see + * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister. + * asn1.type.builtin.CHOICE) + */ + public Object visit(CHOICE data) throws Exception { + return processStructured(data); + } + + /* + * (non-Javadoc) + * + * @see + * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister. + * asn1.type.builtin.SEQUENCE_OF) + */ + public Object visit(SEQUENCE_OF data) + throws Exception { + return processCollection(data); + } + + /* + * (non-Javadoc) + * + * @see + * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister. + * asn1.type.builtin.SEQUENCE) + */ + public Object visit(SEQUENCE data) throws Exception { + return processStructured(data); + } + + /* + * (non-Javadoc) + * + * @see + * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister. + * asn1.type.builtin.SET_OF) + */ + public Object visit(SET_OF data) + throws Exception { + return processCollection(data); + } + + /* + * (non-Javadoc) + * + * @see + * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister. + * asn1.type.builtin.SET) + */ + public Object visit(SET data) throws Exception { + return processStructured(data); + } + + /* + * (non-Javadoc) + * + * @see + * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister. + * asn1.type.StringType) + */ + public Object visit(StringType data) throws Exception { + return data.stringValue(); + } + + /* + * (non-Javadoc) + * + * @see + * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister. + * asn1.type.TimeType) + */ + public Object visit(TimeType data) throws Exception { + return data.date(); + } + + /* + * (non-Javadoc) + * + * @see + * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister. + * asn1.type.UnknownType) + */ + public Object visit(UnknownType data) throws Exception { + ASN1DecodingException ex = new ASN1DecodingException(); + ex.setMessage("UnkonwnType is not supported.", null, + UnknownType.class, null, data); + throw ex; + } + + /** + * Processes structured type (i.e. 'SEQUENCE', 'SET' and 'CHOICE') + * object. + * + * @param data + * The ASN.1 structured type object. + * @return Translated POJO instance. + * @throws Exception + * When an error occurred while translation process. + */ + private Object processStructured(StructuredType data) + throws Exception { + ASN1JavaList javaList = field.getAnnotation(ASN1JavaList.class); + Object component; + if (javaList != null) { + component = javaList.value().newInstance(); + } else { + component = field.getType().newInstance(); + } + data.accept(new StructureEncoder(component)); + return component; + } + + /** + * Processes collection type (i.e. 'SEQUENCE OF' and 'SET OF') + * object. + * + * @param data + * The ASN.1 collection type object. + * @return Translated POJO instance. + * @throws Exception + * When an error occurred while translation process. + */ + private Object processCollection(CollectionType data) + throws Exception { + List list = new ArrayList(); + for (ASN1Type component : data.collection()) { + list.add(component.accept(new ElementEncoder(field))); + } + return list; + } + + } + + } + +}