001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one
003     * or more contributor license agreements.  See the NOTICE file
004     * distributed with this work for additional information
005     * regarding copyright ownership.  The ASF licenses this file
006     * to you under the Apache License, Version 2.0 (the
007     * "License"); you may not use this file except in compliance
008     * with the License.  You may obtain a copy of the License at
009     *
010     *  http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing,
013     * software distributed under the License is distributed on an
014     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015     * KIND, either express or implied.  See the License for the
016     * specific language governing permissions and limitations
017     * under the License.
018     */
019    
020    package org.apache.geronimo.deployment.service;
021    
022    import java.beans.BeanInfo;
023    import java.beans.IntrospectionException;
024    import java.beans.Introspector;
025    import java.beans.PropertyDescriptor;
026    import java.beans.PropertyEditorSupport;
027    import java.lang.reflect.Method;
028    
029    import javax.xml.namespace.QName;
030    
031    import org.apache.geronimo.common.DeploymentException;
032    import org.apache.geronimo.common.propertyeditor.PropertyEditorException;
033    import org.apache.geronimo.deployment.javabean.xbeans.BeanPropertyType;
034    import org.apache.geronimo.deployment.javabean.xbeans.JavabeanDocument;
035    import org.apache.geronimo.deployment.javabean.xbeans.JavabeanType;
036    import org.apache.geronimo.deployment.javabean.xbeans.PropertyType;
037    import org.apache.geronimo.crypto.EncryptionManager;
038    import org.apache.xmlbeans.XmlException;
039    import org.apache.xmlbeans.XmlOptions;
040    
041    /**
042     *
043     * @version $Rev: 706640 $ $Date: 2008-10-21 14:44:05 +0000 (Tue, 21 Oct 2008) $
044     */
045    public class JavaBeanXmlAttributeEditor extends PropertyEditorSupport {
046        private static final QName QNAME = JavabeanDocument.type.getDocumentElementName();
047        private static final Class[] PRIMITIVES_CLASSES = new Class[] {String.class,
048            Boolean.class,
049            Character.class,
050            Byte.class,
051            Short.class,
052            Integer.class,
053            Long.class,
054            Float.class,
055            Double.class
056        };
057    
058        private final Class javaBeanClazz;
059        private final XmlAttributeBuilder xmlAttributeBuilder;
060        
061        public JavaBeanXmlAttributeEditor(Class clazz) {
062            if (null == clazz) {
063                throw new IllegalArgumentException("clazz is required");
064            }
065            this.javaBeanClazz = clazz;
066            
067            xmlAttributeBuilder = newXmlAttributeBuilder();
068        }
069    
070        protected JavaBeanXmlAttributeBuilder newXmlAttributeBuilder() {
071            return new JavaBeanXmlAttributeBuilder();
072        }
073    
074        @Override
075        public void setAsText(String text) throws IllegalArgumentException {
076            try {
077                JavabeanDocument document = JavabeanDocument.Factory.parse(text);
078                JavabeanType javaBeanType = document.getJavabean();
079                
080                Object javabean = xmlAttributeBuilder.getValue(javaBeanType,
081                    javaBeanClazz.getName(),
082                    getClass().getClassLoader());
083    
084                setValue(javabean);
085            } catch (XmlException e) {
086                throw new PropertyEditorException(e);
087            } catch (DeploymentException e) {
088                throw new PropertyEditorException(e);
089            }
090        }
091    
092        @Override
093        public String getAsText() {
094            JavabeanType javabeanType = getJavabeanType(getValue());
095            
096            XmlOptions xmlOptions = new XmlOptions();
097            xmlOptions.setSaveSyntheticDocumentElement(QNAME);
098            xmlOptions.setSavePrettyPrint();
099            return javabeanType.xmlText(xmlOptions);
100        }
101    
102        protected JavabeanType getJavabeanType(Object javaBean) {
103            JavabeanType javabeanType = JavabeanType.Factory.newInstance();
104    
105            javabeanType.setClass1(javaBean.getClass().getName());
106            
107            PropertyDescriptor[] propertyDescriptors;
108            try {
109                BeanInfo beanInfo = Introspector.getBeanInfo(javaBean.getClass());
110                propertyDescriptors = beanInfo.getPropertyDescriptors();
111            } catch (IntrospectionException e) {
112                throw new IllegalStateException("See nested", e);
113            }
114    
115            for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
116                handle(javaBean, propertyDescriptor, javabeanType);
117            }
118            
119            return javabeanType;
120        }
121        
122        protected void handle(Object javaBean, PropertyDescriptor propertyDescriptor, JavabeanType javabeanType) {
123            Method readMethod = propertyDescriptor.getReadMethod();
124            if (null == readMethod) {
125                return;
126            } else if (readMethod.isAnnotationPresent(DoNotPersist.class) || readMethod.getName().equals("getClass")) {
127                return;
128            }
129            
130            Object value;
131            try {
132                value = readMethod.invoke(javaBean, null);
133            } catch (Exception e) {
134                throw new IllegalStateException("See nested", e);
135            }
136            if (null == value) {
137                return;
138            }
139            
140            if (isPrimitive(value)) {
141                PropertyType propertyType = javabeanType.addNewProperty();
142                propertyType.setName(propertyDescriptor.getName());
143                
144                String valueAsString = value.toString();
145                if (readMethod.isAnnotationPresent(EncryptOnPersist.class)) {
146                    valueAsString = EncryptionManager.encrypt(valueAsString);
147                }
148                
149                propertyType.setStringValue(valueAsString);
150            } else {
151                JavabeanType nestedJavabeanType = getJavabeanType(value);
152                
153                BeanPropertyType propertyType = javabeanType.addNewBeanProperty();
154                propertyType.setName(propertyDescriptor.getName());
155                propertyType.setJavabean(nestedJavabeanType);
156            }
157        }
158        
159        protected boolean isPrimitive(Object propertyValue) {
160            Class valueClass = propertyValue.getClass();
161            for (Class primitiveClass : PRIMITIVES_CLASSES) {
162                if (valueClass.equals(primitiveClass)) {
163                    return true;
164                }
165            }
166            return false;
167        }
168        
169    }